当前位置: 首页 > news >正文

剑指 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);
    }
}

含有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);
    }
}

允许重复选择元素的组合

给定一个无重复元素的正整数数组 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);
    }
}

含有重复元素集合的组合

给定一个可能有重复数字的整数数组 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);
        }
    }
}

相关文章:

  • 前端小tips(持续更新)
  • matlab读取文件
  • php __destruct反序列化原理
  • 通俗易懂,一文学会前端缓存
  • python常用基础笔记
  • centos设置root免密自动登陆
  • JuiceFS 在多云存储架构中的应用 | 深势科技分享
  • 【LeetCode】思维向题笔记总结(持续更新)
  • springboot+vue农产品销售配送网站
  • ISE的FPGA程序加载与固化——Omapl138/TMS320C6748+FPGA核心板
  • SAP ABAP 定义事件以及处理事件
  • 西瓜书-2习题
  • 中国LED封装行业发展前景预测与投资战略规划分析报告
  • 传出神经系统分为哪两类,传出神经的分类与功能
  • [最新]ubuntu22.04安装kubernetes1.25 k8s1.25
  • [nginx文档翻译系列] 控制nginx
  • classpath对获取配置文件的影响
  • create-react-app做的留言板
  • IP路由与转发
  • Java 最常见的 200+ 面试题:面试必备
  • JavaScript的使用你知道几种?(上)
  • Java教程_软件开发基础
  • React16时代,该用什么姿势写 React ?
  • SpiderData 2019年2月16日 DApp数据排行榜
  • springboot_database项目介绍
  • Vue全家桶实现一个Web App
  • vue自定义指令实现v-tap插件
  • 给新手的新浪微博 SDK 集成教程【一】
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 简析gRPC client 连接管理
  • 聚类分析——Kmeans
  • 看域名解析域名安全对SEO的影响
  • 删除表内多余的重复数据
  • 使用common-codec进行md5加密
  • 王永庆:技术创新改变教育未来
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 应用生命周期终极 DevOps 工具包
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • # Panda3d 碰撞检测系统介绍
  • $().each和$.each的区别
  • (3)选择元素——(17)练习(Exercises)
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (python)数据结构---字典
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (二)正点原子I.MX6ULL u-boot移植
  • (分布式缓存)Redis持久化
  • (附源码)计算机毕业设计高校学生选课系统
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (原創) 如何刪除Windows Live Writer留在本機的文章? (Web) (Windows Live Writer)
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • .bat批处理(二):%0 %1——给批处理脚本传递参数