算法题中的子集,排列,组合

0.353字数 802阅读 157

子集

例:[1,2,3] 的所有子集
结果 [],[1],[1,2],[1,2,3],[1,3],[2],[2,3],[3]

算法原理描述

条件:集合中的元素不可重复,可按任意顺序排列
算法过程:在第一个位置枚举集合中的所有元素,在每个元素的下一位置枚举所有在它之后的元素,之后表示在集合中的顺序。在每加入一个新元素时,形成一个结果。在当前位置枚举完所有可以枚举的元素后,返回上一层。
算法过程举例:
[]            空集也算一个子集
[1],         在第一个位置枚举集合中的所有元素,即1,2,3,第一次是 1
[1,2],      在第二个位置枚举集合中 1 之后的元素,即是 2 和 3,第一次是 2
[1,2,3],   在第三个位置枚举集合中 2 之后的元素,只有 3 ,枚举完就返回第二个位置
[1,3],      在第二个位置枚举集合中 1 之后的元素,第二次是 3,枚举完返回第一个位置
[2],         在第一个位置枚举集合中的所有元素,第二次是 2
[2,3],      在第二个位置枚举集合中 2 之后的元素,只有 3,枚举完返回第一个位置
[3]          在第一个位置枚举集合中的所有元素,第三次是 3,枚举完,结束

算法的动态图演示

算法代码

List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> list = new ArrayList<>();
        backtrack(list, new ArrayList<>(), nums, 0);
        return list;
}

void backtrack(List<List<Integer>> list , List<Integer> tempList, int [] nums, int start){
        list.add(new ArrayList<>(tempList));
        for(int i = start; i < nums.length; i++){
            tempList.add(nums[i]);
            backtrack(list, tempList, nums, i + 1);
            tempList.remove(tempList.size() - 1);
        }
}

看明白第一个,下面两个就容易理解了

 

排列

例:[1,2,3] 的所有排列情况
结果:[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]

算法原理描述

条件:集合中的元素不可重复,可按任意顺序排列
算法过程:在第一个位置枚举集合中的所有元素,在每个元素的下一位置枚举所有集合中且在前面的位置没有出现过的元素。在元素数量给出集合的元素数量相等时,形成一个结果。在当前位置枚举完所有可以枚举的元素后,返回上一层。

算法代码

List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> list = new ArrayList<>();
        backtrack(list, new ArrayList<>(), nums);
        return list;
}

void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums){
        if(tempList.size() == nums.length){
            list.add(new ArrayList<>(tempList));
        } else {
            for(int i = 0; i < nums.length; i++) {
                if(tempList.contains(nums[i])) continue;
                tempList.add(nums[i]);
                backtrack(list, tempList, nums);
                tempList.remove(tempList.size() - 1);
            }
        }
}

 

组合

例:在 [2,3,5] 中选任意元素 (可以重复选择同一个) ,之和为 8
结果:[2,2,2,2],[2,3,3],[3,5]

算法原理描述

条件:集合中的元素不可重复,按数字顺序从小到大排列
算法过程:在第一个位置枚举集合中的所有元素,在每个元素的下一位置枚举所有在它之后的元素 (包括它),之后表示在集合中的顺序。在所有元素的和等于 8 时,形成一个结果。在所有元素的和大于 8 时,返回上一层。

算法代码

List<List<Integer>> combinationSum(int[] nums, int target) {
        List<List<Integer>> list = new ArrayList<>();
        Arrays.sort(nums);
        backtrack(list, new ArrayList<>(), nums, target, 0);
        return list;
}

void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, int remain, int start){
        if(remain < 0) return;
        else if(remain == 0) list.add(new ArrayList<>(tempList));
        else{ 
            for(int i = start; i < nums.length; i++){
                tempList.add(nums[i]);
                backtrack(list, tempList, nums, remain - nums[i], i); 
                tempList.remove(tempList.size() - 1);
            }
        }
}

代码引用自https://leetcode.com/problems/subsets/discuss/27281/A-general-approach-to-backtracking-questions-in-Java-(Subsets-Permutations-Combination-Sum-Palindrome-Partitioning)

推荐阅读更多精彩内容