順列と組み合わせの問題の要約:(遡及的方法の要約)

1.繰り返される番号のないシーケンスが与えられた場合、可能なすべての順列を返します。

例:

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

まず、テンプレートについて考えます。

      public void dfs(int k){
        if (k==nums.length){
            System.out.println(tmp);    //排列完毕 打印。
            return;
        }
        for(int i=0;i<nums.length;i++ ){
            tmp.set(k,nums[i]);          //从第0位开始依次赋值
            dfs(k+1);
        }
    }

次のコードを書く

import java.util.*;

class Solution {
    List<List<Integer>> res;
    List<Integer> tmp = new ArrayList<>();
    boolean[] used ;
    public List<List<Integer>> permute(int[] nums) {
        used = new boolean[nums.length];                    //初始化
        for(int i=0;i<used.length;i++){
            used[i] =false;
            tmp.add(0);
        }

        res = new ArrayList<>();
        dfs(0, nums);
        return res;
    }

    public void dfs(int k, int[] nums) {            //套模板
        if (k == nums.length) {
            res.add(new ArrayList<>(tmp));    //注意这里
        
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (!used[i]) {
              
                tmp.set(k,nums[i]);
                used[i] = true;
                dfs(k + 1, nums);
                used[i] = false;
        
            }
        }
    }

}

考え直して問題の解決策を読んでください:コードの主な違いはここでもほとんど同じです:()

  // tmp.add(0); 注释掉

public void dfs(int k, int[] nums) {            //套模板
        if (k == nums.length) {
            res.add(new ArrayList<>(tmp));
            System.out.println("out" + tmp);
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (!used[i]) {
                tmp.add(nums[i]);            
                used[i] = true;
                dfs(k + 1, nums);
                used[i] = false;
                tmp.remove(tmp.size()-1);    //回溯 还原状态
            }
        }
    }

2.フルアレンジII

繰り返される番号を含むことができるシーケンス番号を指定すると、繰り返されないすべての順列を任意の順序で返します。

 

例1:

入力:nums = [1,1,2]
出力:
[
 [1,1,2]、
 [1,2,1] [2,1,1]]

考え方は上記とは異なり、

方法1:resで直接重複排除できます

方法2:最初に並べ替えて、バックトラック時にプルーニングします。解決策は次のように参照できます:剪定のバックトラック
 

            if (used[i])
                continue;
            if(i>0 &&nums[i]==nums[i-1]&&!used[i-1])  //如果相等,且前一个没有使用
                continue;

 

 

3、

2つの整数nkが与えられた場合、1 ... nのk個の可能なすべての組み合わせ返します

例:

输入: n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]
public class Solution {
    List<List<Integer>> res;
    List<Integer> tmp = new ArrayList<>();

    public static void main(String[] args) {
        Solution s = new Solution();
        s.combine(4,2);
    }

    public List<List<Integer>> combine(int n, int kk) {
        res = new ArrayList<>();
        if (kk <= 0 || n < kk) {
            return res;
        }
        dfs(1,kk,n);
        return res;
    }

    public void dfs(int b,int kk,int n) {            //套模板
        if (tmp.size()==kk) {
            res.add(new ArrayList<>(tmp));
            System.out.print(tmp);
            return;
        }
        for (int i = b; i <=n; i++) {
                tmp.add(i);
                dfs(i+1,kk,n);            //这里的不同点是i+1  不是上面排列中的k [[1, 2][1, 3][1, 4][2, 3][2, 4][3, 4]]
                // 如果改成上面排列中的的k(也就是改成b+1) [[1, 2][1, 3][1, 4][2, 2][2, 3][2, 4][3, 2][3, 3][3, 4][4, 2][4, 3][4, 4]]
                // 改成b [[1, 1][1, 2][1, 3][1, 4][2, 1][2, 2][2, 3][2, 4][3, 1][3, 2][3, 3][3, 4][4, 1][4, 2][4, 3][4, 4]]
                tmp.remove(tmp.size()-1);
        }
    }

}

 

おすすめ

転載: blog.csdn.net/yu1336199790/article/details/112265586