web-dev-qa-db-ja.com

リストのすべての可能な順列を再帰的に生成する

リスト内のすべてのアイテムを再帰的に生成しようとしています。これと同様の質問に対するいくつかの解決策を見てきましたが、コードを機能させることができませんでした。誰かが私のコードを修正する方法を指摘できますか?

これは、Javaの人々だけでなく、すべてのS/O'erに開かれています。

(また、SO例外)でクラッシュすることに注意する必要があります。

入力例:[1、2、3]

出力:[1、2、3] [1、3、2] [2、1、3] [2、3、1] [3、1、2] [3、2、1]

//allPossibleItems is an AL of all items 

//this is called with generatePerm(null, new ArrayList<Item>);

private void generatePerm(Item i, ArrayList<Item> a) {
      if(i != null) { a.add(i); }
      if (a.size() == DESIRED_SIZE){
          permutations.add(a);
          return;
      }
      for(int j = 0; j < allPossibleItems.size(); j ++) {
          if(allPossibleItems.get(j) != i)
            generatePerm(allPossibleItems.get(j), a);
      }
  }
13
varatis

allPossibleItemsにxとyの2つの異なる要素が含まれている場合は、DESIRED_SIZEに達するまで、xとyをリストに続けて書き込みます。それはあなたが本当に欲しいものですか? DESIRED_SIZEを十分に大きく選択すると、スタックでの再帰呼び出しが多すぎるため、SO例外です。

私がすること(オリジナルに重複/重複がない場合)は次のとおりです。

  public <E> List<List<E>> generatePerm(List<E> original) {
     if (original.isEmpty()) {
       List<List<E>> result = new ArrayList<>(); 
       result.add(new ArrayList<>()); 
       return result; 
     }
     E firstElement = original.remove(0);
     List<List<E>> returnValue = new ArrayList<>();
     List<List<E>> permutations = generatePerm(original);
     for (List<E> smallerPermutated : permutations) {
       for (int index=0; index <= smallerPermutated.size(); index++) {
         List<E> temp = new ArrayList<>(smallerPermutated);
         temp.add(index, firstElement);
         returnValue.add(temp);
       }
     }
     return returnValue;
   }
23
DaveFar

問題は、再帰呼び出しを行う前に clone ArrayListを実行する必要があることです。それ以外の場合は、常に同じArrayListに追加します。

//allPossibleItems is an AL of all items 

//this is called with generatePerm(null, new ArrayList<Item>);

private void generatePerm(Item i, ArrayList<Item> a) {
      if(i != null) { a.add(i); }
      if (a.size() == DESIRED_SIZE){
          permutations.add(a);
          return;
      }
      for(int j = 0; j < allPossibleItems.size(); j ++) {
          if(!a.contains(allPossibleItems.get(j))){
            ArrayList<Item> b = clone(a);
            generatePerm(allPossibleItems.get(j), b);
          }
      }
  }

グーグルは私をこの質問に導きます。以下の方法は他の方法よりも速いことがわかりました。

基本的に、私はSetを使用して順列を再帰的に生成します。説明のために、最初の位置はすべての可能な値を保持でき、2番目の位置は最初の値を除くすべての可能な値を保持できます。最後の位置に到達したとき、可能性は1つだけです。

再帰関数のパラメータに関しては、(1)currentstringとしてすでに記録されているものを渡します。 (2)結果を保持するArraylistを渡します--list_of_permutes(3)現在の数を選択するセットを渡します--currentnums。最後のレベルでは、完全な順列があり、それがarraylist --list_of_permutesに追加され、これが上向きに返されます。

public static ArrayList recurse_nums(Set<Integer> currentnums, String currentstring, ArrayList list_of_permutes){
    if(currentnums.size()==1){
        int elem = currentnums.iterator().next();
        list_of_permutes.add(currentstring + Integer.toString(elem));
        return list_of_permutes;
    }
    for(int a:currentnums){
        String newstring = currentstring + a;
        Set<Integer> newnums = new HashSet<>();
        newnums.addAll(currentnums);
        newnums.remove(a);
        recurse_nums(newnums, newstring,list_of_permutes);
    }
    return list_of_permutes;
}

これは、次のようなものから呼び出すことができます。

public static ArrayList permute_array(int[] arr){
    Set<Integer> currentnums = new HashSet<>();
    for (int i = 0; i < arr.length; i++) {currentnums.add(arr[i]);}
    ArrayList permutations = new ArrayList();
    recurse_nums(currentnums,"",permutations);
    return permutations;
}
1
Rahul Madhavan

開始を固定してから、交換を続けることができます。これは、理解するのが最も簡単なアプローチの1つです。

public class PermutationListRecursion {

    private Set<List<Integer>> permList = new HashSet<>();

    public static void main(String[] args) {
        PermutationListRecursion pt = new PermutationListRecursion();
        Integer[] nums = { 1, 2, 3 };
        pt.permute(nums);
        System.out.println(pt.permList);
    }

    public void permute(Integer[] nums) {
        permutation(0, nums.length - 1, nums);
    }

    public void permutation(int start, int end, Integer[] nums) {
        if (start == end) {
            permList.add(new ArrayList<Integer>(Arrays.asList(nums)));
        }
        for (int i = start; i <= end; i++) {
            permList.add(swap(nums, start, i));
            permutation(start + 1, end, nums);
            permList.add(swap(nums, start, i));
        }
    }

    private List<Integer> swap(Integer[] arr, int a, int b) {
        if (a == b) {
            return new ArrayList<>(Arrays.asList(arr));
        }
        Integer temp = arr[b];
        arr[b] = arr[a];
        arr[a] = temp;
        return new ArrayList<>(Arrays.asList(arr));
    }
}
0
Pritam Banerjee

private List generatePerm(List a, int depth) {
   // this is the method definition you want
   // to generate all permutations, you need cycle thru all elements in your list and for each element
   // add that element to each member of generatePerm(a, depth - 1);
   // if you want combinations, you need to remove the element and then call
   /// generateCombinations with the remaining list 
}
0
ControlAltDel