• 剑指 Offer II 079+080+081+082


    所有子集

    给定一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

    解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

    分析:

    递归实现。定义函数 dfs ( cur , n ) \text{dfs}(\textit{cur}, n) dfs(cur,n) 参数表示当前位置是 cur \textit{cur} cur,原序列总长度为 n。原序列的每个位置在答案序列中的状态有被选中和不被选中两种,用 t 数组存放已经被选出的数字。在进入 dfs ( cur , n ) \text{dfs}(\textit{cur}, n) dfs(cur,n) 之前 [ 0 , cur − 1 ] [0, \textit{cur} - 1] [0,cur1]位置的状态是确定的,而 [ cur , n − 1 ] [\textit{cur}, n - 1] [cur,n1] 内位置的状态是不确定的, dfs ( cur , n ) \text{dfs}(\textit{cur}, n) dfs(cur,n) 需要确定 cur 位置的状态,然后求解子问题 dfs ( c u r + 1 , n ) {\text{dfs}(cur + 1}, n) dfs(cur+1,n)。对于 cur 位置,我们需要考虑a[cur] 取或者不取,如果取,我们需要把 a[cur] 放入一个临时的答案数组中(即上面的 t),再执行 dfs ( c u r + 1 , n ) {\text{dfs}(cur + 1}, n) dfs(cur+1,n),执行结束后需要对 t 进行回溯;如果不取,则直接执行 dfs(cur+1,n)。在整个递归调用的过程中,cur 是从小到大递增的,当 cur 增加到 n 的时候,记录答案并终止递归。

    class Solution {
        List<Integer> list = new ArrayList<>();
        List<List<Integer>> res = new ArrayList<>();
        public List<List<Integer>> subsets(int[] nums) {
            dfs(0, nums);
            return res;
    
        }
        public void dfs(int cur, int[] nums){
            if (cur == nums.length){
                res.add(new ArrayList<>(list));
                return;
            }
            list.add(nums[cur]);
            dfs(cur+1, nums);
            list.remove(list.size()-1);
            dfs(cur+1, nums);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    含有K个元素的组合

    给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。

    分析:

    与上一题类似,使用递归来解决。将上一个题的函数dfs中增加一个参数k,即 dfs ( cur , n , k ) \text{dfs}(\textit{cur}, n, k) dfs(cur,n,k),如果当前数组的长度==k则把数组添加到答案中去,同时增加剪枝代码:如果当前数组长度+剩余长度(n-cur+1) < k的话直接舍弃掉下面的递归。

    class Solution {
        List<Integer> list = new ArrayList<>();
        List<List<Integer>> ans = new ArrayList<>();
        public List<List<Integer>> combine(int n, int k) {
            if (k>n) return null;
            dfs(1,n,k);
            return ans;
    
        }
        public void dfs(int cur, int n, int k){
            if (list.size() == k){
                ans.add(new ArrayList<>(list));
                return;
            }
            if (list.size()+(n-cur+1)<k) return;
            list.add(cur);
            dfs(cur+1, n ,k);
            list.remove(list.size()-1);
            dfs(cur+1,n,k);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    允许重复选择元素的组合

    给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。

    candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是不同的。

    对于给定的输入,保证和为 target 的唯一组合数少于 150 个。

    分析:

    dfs+剪枝+回溯。首先顺序的选择candidates的数字,对于当前的数字有两种选择:1. 选, 下次依旧针对这个数选或不选;2. 不选, 直接跳过该数字,后面不选这个数。

    class Solution {
        List<List<Integer>> result = new ArrayList<>();
        public List<List<Integer>> combinationSum(int[] candidates, int target) {
            dfs(candidates, target, 0, new ArrayList<Integer>());
            return result;
        }
    
        public void dfs(int[] candidates, int target, int start, ArrayList<Integer> list) {
            if (target == 0) {
                result.add(new ArrayList(list));
                return;
            }
            if (target < 0 || start >= candidates.length) return;
    
            //对于当前数字candidates[start]
            //选
            list.add(candidates[start]);
            dfs(candidates, target-candidates[start], start, list);
            list.remove(list.size()-1);
            //或者不选
            dfs(candidates, target, start+1, list);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    含有重复元素集合的组合

    给定一个可能有重复数字的整数数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

    candidates 中的每个数字在每个组合中只能使用一次,解集不能包含重复的组合。

    分析:

    定义函数dfs(idx,target):选中candidate[idx],同时与从下标为[idx + 1, candidate.length)中选取元素一起构成和为target的所有不重复组合的集合。为了避免重复的答案,首先要做的就是给数组排序,如果说在同一级递归中,遇到两个相同的数,应该只dfs靠前的那一个一次。原因可以这样理解,如果现在遇到下标位idx,idx + 1的两个数是相同的,那么对于集合dfs(idx, target) 和 dfs(idx + 1, target),后者就是前者的一个子集,所以在同一级递归中,对于相同的数,只应该dfs一次,并且是下标最小的那一个。
    剪枝就是基于很直接的思想,例如:前面已经给数组排序了,如果递归的过程中当前值比target大,那么说明后面的值不可能再找出一组元素和为target,所以此时就可以立即结束递归返回。

    class Solution {
        public List<List<Integer>> combinationSum2(int[] candidates, int target) {
            int n = candidates.length;
            List<List<Integer>> ans = new ArrayList<>();
            Arrays.sort(candidates);
            dfs(candidates, n, 0, target, new ArrayList<>(), ans);
            return  ans;
        }
    
        public void dfs(int[] candidate, int n, int idx, int target, List<Integer> list, List<List<Integer>> ans) {
            if (target == 0) {
                ans.add(new ArrayList<>(list));
                return ;
            }
            for (int i = idx; i < n; i++) {
                if (candidate[i] > target) { // 剪枝
                    break;
                }
                if (i > idx && candidate[i] == candidate[i - 1]) { // 剪枝、避免重复
                    // 因为前面那个同样的数已经经历过dfs,再拿同样的数dfs就会得到重复的答案
                    continue;
                }
                list.add(candidate[i]);
                dfs(candidate, n, i + 1, target - candidate[i], list, ans);
                list.remove(list.size() - 1);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
  • 相关阅读:
    Mac | 使用 Wineskin 在 Mac 上运行 exe 程序
    Vmware 虚拟机连接外网和设置固定IP
    找到了!宝藏公众号合集,新媒体运营小白必须学习
    存储过程基本了解
    Linux上Docker的安装以及作为非运维人员应当掌握哪些Docker命令
    十二、元类和ORM的实现
    寻找写代码感觉(十九)之 分类表格显示优化 之 树形表格展示
    java毕业设计鑫通物流车辆调度系统mp4Mybatis+系统+数据库+调试部署
    项目中执行 npm run xxx 的时候发生了什么?
    IS-IS
  • 原文地址:https://blog.csdn.net/weixin_49546933/article/details/126606788