Efficacement obtenir des sommes triées de la liste triée

voix
17

Vous avez une liste ascendante des chiffres, ce qui est l'algorithme le plus efficace que vous pouvez penser pour obtenir la liste ascendante des sommes de tous les deux numéros dans cette liste. Dans la liste des doublons résultant ne sont pas pertinentes, vous pouvez les supprimer ou les éviter si vous le souhaitez.

Pour être clair, je suis intéressé par l'algorithme. Ne hésitez pas à poster le code dans toutes les langues et le paradigme que vous aimez.

Créé 03/08/2008 à 22:08
source utilisateur
Dans d'autres langues...                            


8 réponses

voix
12

Modifier à partir de 2018: Vous devriez probablement arrêter de lire ceci. (Mais je ne peux pas le supprimer car il est accepté.)

Si vous écrivez les sommes comme ceci:

1 4  5  6  8  9
---------------
2 5  6  7  9 10
  8  9 10 12 13
    10 11 13 14
       12 14 15
          16 17
             18

Vous remarquerez que, depuis M [i, j] <= M [i, j + 1] et M [i, j] <= M [i + 1, j], alors vous avez seulement besoin d'examiner en haut à gauche " coins » et choisir celui le plus bas.

par exemple

  • seulement 1 coin supérieur gauche, choisissez 2
  • seulement 1, choisissez 5
  • 6 ou 8, choisir 6
  • 7 ou 8, choisir 7
  • 9 ou 8, 8 ramasser
  • 9 ou 9, choisissez les deux :)
  • 10 ou 10 ou 10, vous obtenez les
  • 12 ou 11, prendre 11
  • 12 ou 12, choisissez deux
  • 13 ou 13, choisissez deux
  • 14 ou 14, choisissez deux
  • 15 ou 16, choisissez 15
  • seulement 1, choisissez 16
  • seulement 1, choisissez 17
  • seulement 1, choisissez 18

Bien sûr, quand vous avez beaucoup de coins supérieurs gauche puis cette solution échoit.

Je suis assez sûr que ce problème est Ω (n²), parce que vous devez calculer les sommes pour chaque M [i, j] - à moins que quelqu'un a un meilleur algorithme pour la somme :)

Créé 18/09/2008 à 22:41
source utilisateur

voix
4

Plutôt que de coder ceci, je me dis que je vais pseudo-code dans les étapes et expliquer ma logique, de sorte que de meilleurs programmeurs peuvent faire des trous dans ma logique, si nécessaire.

Sur la première étape, nous commençons avec une liste de numéros longueur n. Pour chaque numéro, nous devons créer une liste de n-1 longueur becuase nous n'ajoutons un numéro à lui-même. À la fin, nous avons une liste d'environ n listes triée qui a été généré en O (n ^ 2) temps.

step 1 (startinglist) 
for each number num1 in startinglist
   for each number num2 in startinglist
      add num1 plus num2 into templist
   add templist to sumlist
return sumlist 

À l'étape 2 parce que les listes ont été classées par la conception (ajouter un numéro à chaque élément dans une liste triée et la liste sera toujours triée) nous pouvons simplement faire une mergesort en fusionnant chaque liste ensemble plutôt que mergesorting l'ensemble du lot. En fin de compte cela devrait prendre O (n ^ 2) temps.

step 2 (sumlist) 
create an empty list mergedlist
for each list templist in sumlist
   set mergelist equal to: merge(mergedlist,templist)
return mergedlist

La méthode de fusion serait alors l'étape de fusion normale avec un chèque pour vous assurer qu'il n'y a pas des sommes en double. Je ne vais pas écrire cela parce que tout le monde peut regarder mergesort.

Il y a donc ma solution. L'algorithme complet est O (n ^ 2) fois. Ne hésitez pas à signaler des erreurs ou des améliorations.

Créé 04/08/2008 à 00:06
source utilisateur

voix
2

Vous pouvez le faire en deux lignes en python avec

allSums = set(a+b for a in X for b in X)
allSums = sorted(allSums)

Le coût de c'est n ^ 2 (peut-être un facteur de journal supplémentaire pour l'ensemble?) Pour l'itération et s * log (s) pour le tri où s est la taille de l'ensemble.

La taille de l'ensemble pourrait être aussi grand que n * (n-1) / 2 par exemple, si X = [1,2,4, ..., 2 ^ n]. Donc, si vous voulez générer cette liste, il faudra au moins n ^ 2/2 dans le pire des cas, puisque c'est la taille de la sortie.

Toutefois , si vous voulez sélectionner les premiers éléments k du résultat , vous pouvez le faire en O (KN) en utilisant un algorithme de sélection pour les matrices X + Y triées par Frederickson et Johnson ( voir ici pour plus de détails gores) . Bien que cela puisse probablement être modifié pour les générer en ligne en réutilisant le calcul et obtenir un générateur efficace pour cet ensemble.

@deuseldorf, Peter Il y a une certaine confusion au sujet (n!) Je doute sérieusement voulu deuseldorf "n factoriels" mais simplement "n, (très heureux)!"

Créé 11/08/2008 à 15:47
source utilisateur

voix
1

Peu importe ce que vous faites, sans contraintes supplémentaires sur les valeurs d'entrée, vous ne pouvez pas faire mieux que O (n ^ 2), simplement parce que vous devez parcourir toutes les paires de nombres. L'itération dominera le tri (que vous pouvez faire en O (n log n) ou plus rapide).

Créé 18/09/2008 à 23:15
source utilisateur

voix
1

Cette question a été éprouvante mon cerveau pendant environ un jour maintenant. Impressionnant.

Quoi qu'il en soit, vous ne pouvez pas sortir de la nature n ^ 2 facilement, mais vous pouvez faire un peu mieux avec la fusion puisque vous pouvez lié la plage d'insérer chaque élément.

Si vous regardez toutes les listes que vous générez, ils ont la forme suivante:

(a[i], a[j]) | j>=i

Si vous retournez 90 degrés, vous obtenez:

(a[i], a[j]) | i<=j

Maintenant, le processus de fusion devrait prendre deux listes iet i+1(qui correspondent à des listes où le premier membre est toujours a[i]et a[i+1]), vous pouvez lié la plage d'insérer l' élément (a[i + 1], a[j])dans la liste ipar l'emplacement (a[i], a[j])et l'emplacement (a[i + 1], a[j + 1]).

Cela signifie que vous devez fusionner dans le sens inverse en termes de j. Je ne sais pas (encore) si vous pouvez tirer parti de cette face jaussi, mais il semble possible.

Créé 21/08/2008 à 19:16
source utilisateur

voix
1

Dans SQL:

create table numbers(n int not null)
insert into numbers(n) values(1),(1), (2), (2), (3), (4)


select distinct num1.n+num2.n sum2n
from numbers num1
inner join numbers num2 
    on num1.n<>num2.n
order by sum2n

C # LINQ:

List<int> num = new List<int>{ 1, 1, 2, 2, 3, 4};
var uNum = num.Distinct().ToList();
var sums=(from num1 in uNum
        from num2 in uNum 
        where num1!=num2
        select num1+num2).Distinct();
foreach (var s in sums)
{
    Console.WriteLine(s);
}
Créé 09/08/2008 à 00:05
source utilisateur

voix
1

Le mieux que je pouvais venir avec est de produire une matrice des sommes de chaque paire, puis fusionner les rangées ensemble, une sorte de la fusion. Je me sens comme si je manque un aperçu simple qui révélera une solution beaucoup plus efficace.

Mon algorithme, en Haskell:

matrixOfSums list = [[a+b | b <- list, b >= a] | a <- list]

sortedSums = foldl merge [] matrixOfSums

--A normal merge, save that we remove duplicates
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys) = case compare x y of
    LT -> x:(merge xs (y:ys))
    EQ -> x:(merge xs (dropWhile (==x) ys))
    GT -> y:(merge (x:xs) ys)

J'ai trouvé une légère amélioration, qui est plus favorable au codage à base de flux-paresseux. Au lieu de fusionner les colonnes PAIRE, fusionner tous à la fois. L'avantage étant que vous commencez à obtenir des éléments de la liste immédiatement.

-- wide-merge does a standard merge (ala merge-sort) across an arbitrary number of lists
-- wideNubMerge does this while eliminating duplicates
wideNubMerge :: Ord a => `a` -> [a]
wideNubMerge ls = wideNubMerge1 $ filter (/= []) ls
wideNubMerge1 [] = []
wideNubMerge1 ls = mini:(wideNubMerge rest)
    where mini = minimum $ map head ls
          rest = map (dropWhile (== mini)) ls

betterSortedSums = wideNubMerge matrixOfSums

Toutefois, si vous savez que vous allez utiliser toutes les sommes, et il n'y a aucun avantage à obtenir certains d'entre eux plus tôt, aller avec « foldl merge []», comme il est plus rapide.

Créé 03/08/2008 à 22:36
source utilisateur

voix
-4

Si vous êtes à la recherche d'une solution agnostique vraiment la langue, alors vous serez très déçu à mon avis, parce que vous serez coincé avec une boucle et quelques conditionals. Toutefois, si vous l'avez ouvert jusqu'à langages fonctionnels ou des caractéristiques linguistiques fonctionnelles (je vous regarde LINQ) alors mes collègues peuvent remplir cette page avec des exemples élégants Ruby, Lisp, Erlang, et d'autres.

Créé 03/08/2008 à 22:24
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more