найти пару чисел в массиве, которые добавляют к заданной сумме
вопрос: учитывая несортированный массив положительных целых чисел, можно ли найти пару целых чисел из этого массива, которые суммируются до заданной суммы?
ограничения: это должно быть сделано в O (n) и на месте (без какого-либо внешнего хранилища, такого как массивы, хэш-карты) (вы можете использовать дополнительные переменные/указатели)
Если это невозможно, Может ли быть доказательство того же самого?
19 ответов
если у вас есть отсортированный массив, вы можете найти такую пару в O (n), переместив два указателя к середине
i = 0
j = n-1
while(i < j){
if (a[i] + a[j] == target) return (i, j);
else if (a[i] + a[j] < target) i += 1;
else if (a[i] + a[j] > target) j -= 1;
}
return NOT_FOUND;
сортировка может быть выполнена O (N), если у вас есть привязка к размеру чисел (или если массив уже отсортирован в первую очередь). Даже тогда коэффициент log n очень мал, и я не хочу утруждать себя сбривать его.
доказательство:
если есть решение (i*, j*)
предположим, без потери общности, это i
достигает i*
до j
достигает j*
. С тех пор для всех j'
между j*
и j
известно, что a[j'] > a[j*]
мы можем экстраполировать, что a[i] + a[j'] > a[i*] + a[j*] = target
и, следовательно, все следующие шаги алгоритма приведут к уменьшению j до тех пор, пока он не достигнет j*
(или равное значение) без указания i
шанс продвинуться вперед и "Мисс" решение.
интерпретация в другом направлении аналогична.
An O(N)
время и O(1)
пространственное решение, которое работает с отсортированным массивом:
пусть M
быть значение, которое вы после. Используйте два указателя,X
и Y
. Старт X=0
в начале и Y=N-1
в конце. Вычислить сумму sum = array[X] + array[Y]
. Если sum > M
, затем декремент Y
, в противном случае increment X
. Если указатели пересекаются, то решения не существует.
вы можете отсортировать на месте, чтобы получить это для общего массива, но я не уверен, что есть O(N)
время и O(1)
решение пространства в целом.
это возможно, если массив содержит числа, верхний предел которых известен вам заранее. Затем используйте сортировку подсчета или сортировку radix(o (n)) и используйте алгоритм, предложенный @PengOne.
в противном случае Я не могу придумать решение O(n).Но решение O(nlgn) работает следующим образом:-
сначала отсортируйте массив с помощью сортировки слиянием или быстрой сортировки (для inplace). Найдите, есть ли sum - array_element в этом отсортированном массиве. Можно использовать двоичный поиск что.
So total time complexity: O(nlgn) + O(lgn) -> O(nlgn).
как отметил @PengOne, это невозможно в общей схеме вещей. Но если вы сделаете некоторые ограничения на данные ввода-вывода.
- все элементы все + или все -, если нет, то нужно будет знать диапазон (высокий, низкий) и внести изменения.
- K, сумма двух целых чисел разрежена по сравнению с элементами в целом.
- это нормально, чтобы уничтожить I / P массив A[N].
Шаг 1: переместите все элементы меньше суммы в начало массива, скажем, в N проходах мы разделили массив на [0,K] & [K, N-1] такой,что [0, K] содержит элементы
Шаг 2: поскольку мы знаем границы (от 0 до суммы), мы можем использовать сортировку radix.
Шаг 3: Используйте двоичный поиск на[K], хорошо, что если нам нужно найти дополнительный элемент, нам нужно посмотреть только половину массива A[K]. поэтому в A[k] мы перебираем a[ 0 to K/2 + 1] Нам нужно выполнить двоичный поиск в A[i to K].
Так что всего appx. Время, N + K + K/2 lg (K), где K-количество элементов 0 для суммирования в I / p A[N]
Примечание: Если вы используете подход @PengOne, вы можете сделать шаг 3 в K. таким образом, общее время будет N+2K, что определенно O (N)
мы не используем никакой дополнительной памяти, но уничтожаем массив ввода-вывода, который также не плох, так как у него не было никакого заказа.
во-первых, отсортируйте массив с помощью сортировка radix. Это отбросит вас назад O (kN). Затем переходите в @PengOne предлагаю.
следующий сайт дает простое решение, используя hashset, который видит число, а затем ищет hashset для заданной суммы-текущего числа http://www.dsalgo.com/UnsortedTwoSumToK.php
вот алгоритм O(N). Он полагается на алгоритм удаления дубликатов на месте O(N), и существование хорошей хэш-функции для ints в вашем массиве.
Сначала удалите все дубликаты из массива.
во-вторых, пройдите через массив и замените каждое число x на min (x, S-x), где S-сумма, которую вы хотите достичь.
В-третьих, найдите, есть ли дубликаты в массиве: если " x " дублируется, то "x" и "S-x" должны иметь произошел в исходном массиве, и вы нашли свою пару.
мое решение в Java (временная сложность O (n)), это выведет все пары с заданной суммой
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Map<Integer, Integer> hash = new HashMap<>();
int arr[] = {1,4,2,6,3,8,2,9};
int sum = 5;
for (int i = 0; i < arr.length; i++) {
hash.put(arr[i],i);
}
for (int i = 0; i < arr.length; i++) {
if(hash.containsKey(sum-arr[i])){
System.out.println(i+ " " + hash.get(sum-arr[i]));
}
}
}
}
- используйте count sort для сортировки массива O (n).
-
возьмите два указателя, один из которых начинается с 0-го индекса массива, а другой-с конца массива (n-1).
запустите цикл до low
Sum = arr[low] + arr[high] if(sum == target) print low, high if(sum < target) low++ if(sum > target) high--
Шаг 2 до 10 занимает O(n) время, а подсчет сортировки занимает O (n). Таким образом, общая сложность времени будет O(n).
вот решение ведьма учитывает повторяющиеся записи. Он написан на javascript и работает с использованием отсортированных и несортированных массивов. Решение выполняется в O (n) раз.
var count_pairs_unsorted = function(_arr,x) {
// setup variables
var asc_arr = [];
var len = _arr.length;
if(!x) x = 0;
var pairs = 0;
var i = -1;
var k = len-1;
if(len<2) return pairs;
// tally all the like numbers into buckets
while(i<k) {
asc_arr[_arr[i]]=-(~(asc_arr[_arr[i]]));
asc_arr[_arr[k]]=-(~(asc_arr[_arr[k]]));
i++;
k--;
}
// odd amount of elements
if(i==k) {
asc_arr[_arr[k]]=-(~(asc_arr[_arr[k]]));
k--;
}
// count all the pairs reducing tallies as you go
while(i<len||k>-1){
var y;
if(i<len){
y = x-_arr[i];
if(asc_arr[y]!=undefined&&(asc_arr[y]+asc_arr[_arr[i]])>1) {
if(_arr[i]==y) {
var comb = 1;
while(--asc_arr[_arr[i]] > 0) {pairs+=(comb++);}
} else pairs+=asc_arr[_arr[i]]*asc_arr[y];
asc_arr[y] = 0;
asc_arr[_arr[i]] = 0;
}
}
if(k>-1) {
y = x-_arr[k];
if(asc_arr[y]!=undefined&&(asc_arr[y]+asc_arr[_arr[k]])>1) {
if(_arr[k]==y) {
var comb = 1;
while(--asc_arr[_arr[k]] > 0) {pairs+=(comb++);}
} else pairs+=asc_arr[_arr[k]]*asc_arr[y];
asc_arr[y] = 0;
asc_arr[_arr[k]] = 0;
}
}
i++;
k--;
}
return pairs;
}
начните с обеих сторон массива и медленно продвигайтесь внутрь, подсчитывая, сколько раз каждое число найдено. Как только вы достигнете середины, все числа подсчитываются, и теперь вы можете прогрессировать оба указателя, подсчитывая пары, как вы идете.
он подсчитывает только пары, но может быть переработано в
- найти пары
- найти пары
- найти пары > x
наслаждайтесь!
реализация Ruby
ar1 = [ 32, 44, 68, 54, 65, 43, 68, 46, 68, 56]
for i in 0..ar1.length-1
t = 100 - ar1[i]
if ar1.include?(t)
s= ar1.count(t)
if s < 2
print s , " - " , t, " , " , ar1[i] , " pair ", i, "\n"
end
end
end
в javascript: этот код, когда n больше, то время и количество итераций увеличиваются. Количество тестов, выполненных программой, будет равно ((n*(n/2)+n/2), где n-количество элементов.Заданное число суммы отбрасывается в if (arr[i] + arr[j] = = = 0), где 0 может быть любым заданным числом.
var arr = [-4, -3, 3, 4];
var lengtharr = arr.length;
var i = 0;
var j = 1;
var k = 1;
do {
do {
if (arr[i] + arr[j] === 0) { document.write(' Elements arr [' + i + '] [' + j + '] sum 0'); } else { document.write('____'); }
j++;
} while (j < lengtharr);
k++;
j = k;
i++;
} while (i < (lengtharr-1));
не гарантируется возможность; как выбрана данная сумма?
пример: несортированный массив целых чисел
2, 6, 4, 8, 12, 10
данную сумму:
7
??
вот решение в python:
a = [9, 8, 9, 2, 15, 11, 21, 8, 9, 2, 2, 8, 9, 2, 15, 11, 21, 8, 9, 2, 9, 8, 9, 2, 15, 11, 21, 8, 9, 2, 2, 8, 9, 2, 15, 11, 2, 8, 9, 2, 2, 8,
9, 2, 15, 11, 21, 8, 9, 12, 2, 8, 9, 2, 15, 11, 21, 7, 9, 2, 23, 8, 9, 2, 15, 11, 21, 8, 9, 2, 2, 12, 9, 2, 15, 11, 21, 8, 9, 2, 2,
8, 9, 2, 15, 11, 21, 8, 9, 2, 2, 8, 9, 2, 15, 11, 21, 8, 9, 2, 2, 8, 9, 2, 15, 11, 21, 8, 9, 2, 2, 7.12, 9, 2, 15, 11, 21, 8, 9, 2, 2, 8, 9,
2, 15, 11, 21, 8, 9, 2, 2, 8, 9, 2, 15, 11, 21, 8, 9, 2, 2, 8, 9, 2, 15, 11, 21, 8, 9, 2, 2, 8, 9, 2, 15, 11, 21, 8, 0.87, 78]
i = 0
j = len(a) - 1
my_sum = 8
finded_numbers = ()
iterations = 0
while(OK):
iterations += 1
if (i < j):
i += 1
if (i == j):
if (i == 0):
OK = False
break
i = 0
j -= 1
if (a[i] + a[j] == my_sum):
finded_numbers = (a[i], a[j])
OK = False
print finded_numbers
print iterations
мне задали этот же вопрос во время интервью, и это схема, которую я имел в виду. Осталось сделать улучшение, чтобы разрешить отрицательные числа, но было бы необходимо только изменить индексы. С точки зрения пространства это не хорошо, но я считаю, что время работы здесь будет O(N)+O(N)+O(подмножество N) -> O(N). Возможно, я ошибаюсь.
void find_sum(int *array_numbers, int x){
int i, freq, n_numbers;
int array_freq[x+1]= {0}; // x + 1 as there could be 0’s as well
if(array_numbers)
{
n_numbers = (int) sizeof(array_numbers);
for(i=0; i<n_numbers;i++){ array_freq[array_numbers[i]]++; } //O(N)
for(i=0; i<n_numbers;i++)
{ //O(N)
if ((array_freq[x-array_numbers[i]] > 0)&&(array_freq[array_numbers[i]] > 0)&&(array_numbers[i]!=(x/2)))
{
freq = array_freq[x-array_numbers[i]] * array_freq[array_numbers[i]];
printf(“-{%d,%d} %d times\n”,array_numbers[i],x-array_numbers[i],freq );
// “-{3, 7} 6 times” if there’s 3 ‘7’s and 2 ‘3’s
array_freq[array_numbers[i]]=0;
array_freq[x-array_numbers[i]]=0; // doing this we don’t get them repeated
}
} // end loop
if ((x%2)=0)
{
freq = array_freq[x/2];
n_numbers=0;
for(i=1; i<freq;i++)
{ //O([size-k subset])
n_numbers+= (freq-i);
}
printf(“-{%d,%d} %d times\n”,x/2,x/2,n_numbers);
}
return;
}else{
return; // Incoming NULL array
printf(“nothing to do here, bad pointer\n”);
}
}
критики.в java это зависит от максимального числа в массиве. он возвращает int [], имеющий индексы двух элементов. Это O (N).
public static int[] twoSum(final int[] nums, int target) {
int[] r = new int[2];
r[0] = -1;
r[1] = -1;
int[] vIndex = new int[0Xffff];
for (int i = 0; i < nums.length; i++) {
int delta = 0Xfff;
int gapIndex = target - nums[i] + delta;
if (vIndex[gapIndex] != 0) {
r[0] = vIndex[gapIndex];
r[1] = i + 1;
return r;
} else {
vIndex[nums[i] + delta] = i + 1;
}
}
return r;
}
сначала вы должны найти обратный массив = > сумма минус фактический массив затем проверьте, существует ли какой-либо элемент из этого нового массива в фактическом массиве.
const arr = [0, 1, 2, 6];
const sum = 8;
let isPairExist = arr
.map(item => sum - item) // [8, 7, 6, 2];
.find((item, index) => {
arr.splice(0, 1); // an element should pair with another element
return arr.find(x => x === item);
})
? true : false;
console.log(isPairExist);
наивная двойная петлевая распечатка с производительностью O (n x n) может быть улучшена до линейной производительности O(n) с использованием памяти O(n) для хэш-таблицы следующим образом:
void TwoIntegersSum(int[] given, int sum)
{
Hashtable ht = new Hashtable();
for (int i = 0; i < given.Length; i++)
if (ht.Contains(sum - given[i]))
Console.WriteLine("{0} + {1}", given[i], sum - given[i]);
else
ht.Add(given[i], sum - given[i]);
Console.Read();
}
def pair_sum(arr,k):
counter = 0
lookup = set()
for num in arr:
if k-num in lookup:
counter+=1
else:
lookup.add(num)
return counter
pass
pair_sum([1,3,2,2],4)
решение в python