Question: Etant donné un tableau d’entiers positifs non triés, est-il possible de trouver une paire d’entiers de ce tableau qui totalisent une somme donnée?
Contraintes: Cela devrait être fait dans O(n) et sur place (sans stockage externe comme les tableaux, les tables de hachage) (vous pouvez utiliser des variables/pointeurs supplémentaires).
Si ce n'est pas possible, peut-il y avoir une preuve pour la même chose?
Si vous avez un tableau trié, vous pouvez trouver une telle paire dans O(n) en déplaçant deux pointeurs vers le milieu.
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;
Le tri peut être effectué O(N) si vous avez une limite sur la taille des nombres (ou si le tableau est déjà trié en premier lieu). Même dans ce cas, un facteur de log n est vraiment petit et je ne veux pas prendre la peine de le réduire.
preuve:
S'il existe une solution (i*, j*)
, supposons, sans perte de généralité, que i
atteigne i*
avant que j
atteigne j*
. Puisque pour tout j'
entre j*
et j
, nous savons que a[j'] > a[j*]
nous pouvons extrapoler ce a[i] + a[j'] > a[i*] + a[j*] = target
et, par conséquent, que toutes les étapes suivantes de l’algorithme entraîneront une diminution de j jusqu’à atteindre j*
(ou une valeur égale) sans donner à i
avancer et "rater" la solution.
L'interprétation dans l'autre sens est similaire.
Une solution d'espace O(N)
time et O(1)
qui fonctionne sur un tableau trié:
Soit M
la valeur que vous recherchez. Utilisez deux pointeurs, X
et Y
. Commencez X=0
au début et Y=N-1
à la fin. Calculez la somme sum = array[X] + array[Y]
. Si sum > M
, décrémentez Y
, sinon incrémentez X
. Si les pointeurs se croisent, alors aucune solution n'existe.
Vous pouvez trier sur place pour obtenir ceci pour un tableau général, mais je ne suis pas sûr qu'il existe une solution d'espace O(N)
time et O(1)
en général.
AS @PengOne a mentionné que ce n’était pas possible dans l’ordre général des choses. Mais si vous faites des restrictions sur les données i/p.
Étape 1: Déplacez tous les éléments inférieurs à SUM au début du tableau, comme dans N Passes, nous avons divisé le tableau en [0, K] & [K, N-1], de sorte que [0, K] contient des éléments <= SUM.
Étape 2: Puisque nous connaissons les limites (0 à SUM), nous pouvons utiliser le tri de base.
Étape 3: Utilisez la recherche binaire sur A [K]. Une bonne chose est que si nous avons besoin de trouver un élément complémentaire, il suffit de regarder la moitié du tableau A [K]. donc dans A [k] nous itérons sur A [0 à K/2 + 1] nous devons faire une recherche binaire dans A [i à K].
Donc total appx. le temps est, N + K + K/2 lg (K) où K est le nombre d'éléments entre 0 et Sum en i/p A [N]
Remarque: si vous utilisez l'approche de @ PengOne, vous pouvez effectuer l'étape 3 en K. Le temps total serait donc de N + 2K, ce qui est certainement O(N)
Nous n'utilisons pas de mémoire supplémentaire, mais détruisons le tableau i/p, qui n'est également pas mauvais, car il n'avait aucun ordre pour commencer.
Cela peut être possible si le tableau contient des nombres dont vous connaissez au préalable la limite supérieure. Utilisez ensuite la méthode de comptage ou de tri de base (o (n)) et utilisez l’algorithme suggéré par @PengOne.
Sinon Je ne peux pas penser à la solution O(n). Mais la solution O(nlgn) fonctionne de la manière suivante: -
Commencez par trier le tableau à l'aide du tri par fusion ou du tri rapide (pour in situ). Recherchez si sum - array_element est présent dans ce tableau trié . On peut utiliser la recherche binaire pour cela.
So total time complexity: O(nlgn) + O(lgn) -> O(nlgn).
Tout d’abord, triez le tableau avec radix sort . Cela vous coûtera O (kN). Procédez ensuite comme le suggère @PengOne.
Voici un algorithme O(N). Il repose sur un algorithme de suppression de doublons sur place O(N) , et sur l'existence d'une fonction de hachage correcte pour les ints de votre tableau.
Tout d'abord, supprimez tous les doublons du tableau.
Deuxièmement, parcourez le tableau et remplacez chaque nombre x par min (x, S-x), où S est la somme que vous souhaitez atteindre.
Troisièmement, recherchez s'il y a des doublons dans le tableau: si 'x' est dupliqué, alors 'x' et 'S-x' doivent être apparus dans le tableau d'origine et vous avez trouvé votre paire.
Ma solution en Java (Time Complexity O (n)), cela produira toutes les paires avec une somme donnée
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]));
}
}
}
}
Le site suivant donne une solution simple en utilisant hashset qui voit un numéro, puis cherche dans le hashset un nombre somme-courant donné http://www.dsalgo.com/UnsortedTwoSumToK.php
prenons deux pointeurs on part du 0ème index du tableau, et un autre de la fin du tableau dit (n-1).
exécuter la boucle jusqu'à basse <= haute
Sum = arr[low] + arr[high]
if(sum == target)
print low, high
if(sum < target)
low++
if(sum > target)
high--
Les étapes 2 à 10 prennent O(n) temps, et le tri compte prend O (n). La complexité temporelle totale sera donc O (n).
En javascript: Ce code, lorsque n est supérieur à, augmente le temps et le nombre d'itérations. Le nombre de tests effectués par le programme sera égal à ((n * (n/2) + n/2) où n est le nombre d'éléments. Le nombre total donné est ignoré dans if (arr [i] + arr [j ] === 0) où 0 pourrait être n'importe quel nombre donné.
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));
Voici une solution qui prend en compte les entrées en double. Il est écrit en javascript et fonctionne à l'aide de tableaux triés et non triés. La solution s'exécute dans le temps 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;
}
Commencez des deux côtés de la matrice et avancez lentement en calculant le nombre de fois où chaque nombre est trouvé. Une fois que vous avez atteint le point médian, tous les chiffres sont comptés et vous pouvez maintenant faire progresser les deux pointeurs en comptant les paires au fur et à mesure.
Il ne compte que les paires mais peut être retravaillé
Prendre plaisir!
Ruby implémentation
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
On m'a posé la même question lors d'une interview et c'est le stratagème auquel je pensais. Il reste une amélioration à faire pour permettre les nombres négatifs, mais il ne faudrait que modifier les index. En ce qui concerne l'espace, ce n'est pas bien, mais je pense que le temps de course ici serait O (N) + O (N) + O (sous-ensemble de N) -> O (N). J'ai peut-être tort.
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”);
}
}
Les critiques sont les bienvenues.
En Java, cela dépend du nombre maximum dans un tableau. il retourne un int [] ayant les index de deux éléments .
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;
}
Voici une solution en 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
Une impression naïve à double boucle avec des performances O (n x n) peut être améliorée en performances linéaires O(n) à l'aide de la mémoire O(n) pour la table de hachage comme suit:
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)
La solution en python
Pas garanti d'être possible; comment la somme donnée est-elle sélectionnée?
Exemple: tableau d'entiers non trié
2, 6, 4, 8, 12, 10
Somme donnée:
7
??
Vous devez d’abord trouver le tableau inversé => somme moins le tableau réel Puis vérifier s’il existe un élément de ce nouveau tableau dans le tableau actuel.
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);