web-dev-qa-db-fra.com

Trouver tous les sous-ferrays possibles d'un tableau

Je suis perdue, je ne peux tout simplement pas sembler avoir la tête en arrière-plan/approches de récursivité. Je comprends comment des problèmes de récursion simples comme les facteurs facteurs de travail que je peux même les retrouver à la main. Mais quand il s'agit de retracer des problèmes, je suis tellement perdu. Je continue d'essayer. Son été 5 heures, j'ai lu diverses approches sur les forums et les échanges de pile, mais rien n'a cliqué sur.

Par exemple, disons que j'ai un tableau avec [1,2,3,4] et ma valeur de destination est 5. J'essaie de trouver toutes les combinaisons possibles qui sont égales à ma valeur de destination.

J'ai cassé ce problème plus loin pour le rendre encore plus simple pour que mon moi de comprendre. Je peux d'abord trouver toutes les combinaisons possibles du tableau, puis les transmettre à une autre fonction qui vérifie si la somme de ce tableau équivaut à la valeur de destination et que cela n'imprime-t-il que.

Quelqu'un peut-il conseiller comment aborder cela? Je ne cherche pas de code/réponse Je veux pouvoir penser et imaginer cela dans ma tête clairement.

4
user2733436

Passons à une matrice de taille n. Il y a 2n desserers possibles de ce tableau. Permet de prendre l'exemple de matrice de taille 4: [1, 2, 3, 4]. Il ya deux4 sous-tableaux.

Sous-maquette de l'ensemble vide ([]) est le 0e une (0000). La sous-carrée de [1], est le second (0001), la sous-carrée de [2] est le second ... (0010) et la sous-réseau [1, 2] est le troisième (0011). Vous devriez voir où cela va.

Aucune récursion n'est nécessaire pour cela. L'ensemble des sous-tableaux est la représentation binaire de la ne valeur allant de 0 à 2n - 1.

Avec cette réalisation, la génération de tous les sous-ouvriers pour des tableaux donnés devrait être une affaire triviale d'itération des entiers et les regarder comme des champs de bits pour si un élément particulier est dans la sous-carraille ou non.

Voir aussi Nombre de k Combinaisons pour tous K sur wikipedia.


Je voudrais souligner que c'est probablement la bonne façon de le faire en C et des langues similaires. Essayer de forcer la récursion, des listes et de retrouver ce qui serait autrement un problème itératif simple avec une réponse claire et compréhensible peut ne pas être la meilleure approche.

Notez que d'autres réponses proposées à cela deviennent rapidement des exemples et des solutions de programmation fonctionnelle. La programmation fonctionnelle est géniale. Toutefois, dans une langue non adaptée à une telle tentative de forcer ce paradigme de programmation, il serait semblable à écrire C code dans LISP - ce n'est peut-être pas le meilleur moyen d'aborder le problème.

Je devrais également souligner que le problème affiché à la question est:

Par exemple, disons que j'ai un tableau avec [1,2,3,4] et ma valeur de destination est 5. J'essaie de trouver toutes les combinaisons possibles égales à ma valeur de destination.

Ceci est un problème bien connu connu sous le nom de sous-ensemble sum Problème et a un certain nombre d'approches pour le résoudre ... générer tous les sous-ensembles de la matrice n'est pas requis (ni même souhaité) pour les approches plus rapides pour le résoudre.

5
user40980

Vous voulez énumérer récursivement l'ensemble des sublistes de 1 :: 2 :: 3 :: 4 :: [] Quelles sommes à 5. (Les :: est la notation OCAML pour la construction de la liste.) L'étape récursive dans le traitement de la liste se divise la liste dans sa tête 1 et sa queue 2 :: 3 :: 4 :: [] - pouvons-nous décrire notre ensemble dans ces termes?

Il y a deux types de sublistes de 1 :: 2 :: 3 :: 4 :: [] Quelles sommes à 5:

  • Le premier type consiste en des listes commençant par 1 et suivi d'une liste qui résume à 4 = 5 - 1.
  • Le deuxième type consiste en sublistes de 2 :: 3 :: 4 :: [] Sommation à 5.

Merveilleux! Si nous appelons partition la fonction int list -> int -> int list list Trouver tous les sublistes requis, la description ci-dessus décrit simplement comment définir partition lst Pour les listes lstof longueur n donné sa définition pour des listes de longueur n-1.

Ecrire la fonction dans OCAML est alors SAIMTERFORWARD:

let rec partition lst w =
  if w = 0 then
    [[]]
  else
    match lst with
      | [] -> []
      | hd :: tl -> firstkind hd tl (w - hd) @ partition tl w
and firstkind hd tl w =
  List.map (fun lst -> hd :: lst) (partition tl w)

Je suppose que, dans le but de cet exercice que vous ne voulez pas de répétition. Par exemple, les combinaisons pour [1..4] sont

[[1],[1,2],[1,2,3],[1,2,3,4],[1,2,4],[1,3],[1,3,4],
 [1,4],[2],[2,3],[2,3,4],[2,4],[3],[3,4],[4]]

Sinon, le processus est vraiment identique pour toutes les fonctions récursives: Souvenez-vous vos bases et déterminez votre problème plus important en termes de faible problème.

Nous allons créer une fonction subarrays qui prend une liste et renvoie une liste de listes - une pour chaque combinaison, donc:

subarrays :: [a] -> [[a]]

Le boîtier de base est généralement très facile. Dans ce cas, les sous-bras pour une liste vide est une liste vide, alors:

subarrays [] = []

L'étape récursive pour les fonctions de la liste le casse presque toujours dans le premier élément, appelée "la tête" (notée ici par x) et le reste de la liste, appelé "queue" (indiquée ici par xs). Nous supposons que nous connaissons déjà la bonne réponse pour la queue et que nous utilisons cela pour construire une réponse pour la tête. Ici, nous affectons le symbole combos à la réponse de la queue:

subarrays (x:xs) = let combos = subarrays xs

Jusqu'à présent, c'est un code relativement de la chaudière que vous trouvez sur presque toutes les fonctions récursives sous une forme ou une autre. La partie délicate est maintenant que nous l'avons résolu pour une liste plus petite, comment ajoutons-nous une autre couche?

Pour un exemple, supposons combos contient toutes les solutions pour [2,3,4] et vous construisez une liste qui contient également des solutions contenant 1. Dans ce cas, vous pouvez faire l'une des trois choses pour construire la liste plus grande.

  • Juste 1 par lui-même. ([x])
  • Il suffit d'avoir toutes les autres combos par elles-mêmes. (combos)
  • Avoir tous les autres combos avec un 1 ajouté. (map (x:) combos)

Revenez ensuite une liste contenant toutes ces possibilités:

[x] : map (x:) combos ++ combos

C'est vraiment tout ce qu'il y a. Voici le programme complet de HASKELL avec la fonction de test SUM aussi:

subarrays :: [a] -> [[a]]
subarrays [] = []
subarrays (x:xs) = let combos = subarrays xs
                   in [x] : map (x:) combos ++ combos

combosSumTo :: Int -> [Int] -> [[Int]]
combosSumTo x = filter (\y -> sum y == x) . subarrays

En ce qui concerne la façon dont je suis arrivé avec les trois choses, vous devez simplement avoir à pratiquer et à tester et à répéter. Quand j'ai écrit tout à l'heure, j'ai oublié accidentellement la partie [x], mais qui a montré dans mes tests. L'astuce n'est pas d'essayer de recueillir la pile dans votre tête. Assumez simplement que l'appel récursif vous donne la bonne réponse pour la queue de la liste.

1
Karl Bielefeldt