代码随想录算法训练营第二十四天| 理论基础,77. 组合

 题目与题解

参考资料:回溯法理论基础

带你学透回溯算法(理论篇)| 回溯法精讲!_哔哩哔哩_bilibili

77. 组合 

题目链接:​​​​​​​​​​​​​​77. 组合 

代码随想录题解:77. 组合 

视频讲解:带你学透回溯算法-组合问题(对应力扣题目:77.组合)| 回溯法精讲!_哔哩哔哩_bilibili

带你学透回溯算法-组合问题的剪枝操作(对应力扣题目:77.组合)| 回溯法精讲!_哔哩哔哩_bilibili

解题思路:

        回溯法的题目之前很少做,对于这一道题,手写穷举是很好写的,如果只有两个数的组合,求两层for循环即可,但是当k很大时,就比较难直接暴力写for循环了。

        这一题主要是初步体验一下回溯法的流程,所以直接看答案了。

看完代码随想录之后的想法 

        回溯法的要点:

  1. 回溯法解决的问题都可以抽象为树形结构(N叉树),树的每深入一层相当于递归操作,而在每层上的操作一般都是循环处理。
  2. 每次搜索到了叶子节点,我们就找到了一个结果,因此找到叶子节点一般是终止条件。
  3. 为了提高穷举效率,可以针对N叉树做剪枝操作,避免不必要的递归和循环。

回溯法一般的函数体为:

void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {处理节点;backtracking(路径,选择列表); // 递归回溯,撤销处理结果}
}

对于这道题,其N叉树为

 

每次循环的起始值startIndex就是取1,2,3...的操作,而终止条件就是当前循环的一个符合条件的list已经满了,达到了叶子节点,将结果塞入result的list后,还需要将list最末尾的节点弹出,方便下一次操作。

class Solution {List<List<Integer>> result= new ArrayList<>();LinkedList<Integer> path = new LinkedList<>();public List<List<Integer>> combine(int n, int k) {backtracking(n,k,1);return result;}public void backtracking(int n,int k,int startIndex){if (path.size() == k){result.add(new ArrayList<>(path));return;}for (int i =startIndex;i<=n;i++){path.add(i);backtracking(n,k,i+1);path.removeLast();}}
}

当然,考虑到如果从startIndex到n的元素数目不足k,那么就算循环结束这个path也不会被使用,浪费了时间,可以提前剪枝,因此循环中i的上限设置为n - (k - path.size()) + 1 ,注意path.size()是小于等于k的。这样就完成了剪枝。

class Solution {List<List<Integer>> result = new ArrayList<>();LinkedList<Integer> path = new LinkedList<>();public List<List<Integer>> combine(int n, int k) {combineHelper(n, k, 1);return result;}/*** 每次从集合中选取元素,可选择的范围随着选择的进行而收缩,调整可选择的范围,就是要靠startIndex* @param startIndex 用来记录本层递归的中,集合从哪里开始遍历(集合就是[1,...,n] )。*/private void combineHelper(int n, int k, int startIndex){//终止条件if (path.size() == k){result.add(new ArrayList<>(path));return;}for (int i = startIndex; i <= n - (k - path.size()) + 1; i++){path.add(i);combineHelper(n, k, i + 1);path.removeLast();}}
}

遇到的困难

        我一开始按照答案的思路抄写,但是没有用linkedlist作为存储path的变量而是用了list,在result.add的时候直接插入了path,结果每次输出的结果都是全空的。debug的时候很奇怪,插入result的一瞬间结果是对的,到下一层遍历的时候result里面的元素竟然减少了。就很奇怪。

        查阅了以后才知道,java中的list如果直接被加入list.add(list),传入的是list的引用,而非拷贝。所以即使当时把path加入了result,随着后面回溯时要弹出元素,被引用加入result的path自然也会随之改变。

        正确的做法是每次拷贝一份新的path,即不用result.add(path)而是result.add(new ArrayList<>(path)),这样path就算有任何变化,也不会影响这一份拷贝。

今日收获

        初步学习了一下回溯法的思路,并且用组合这道题为例理解了一下回溯法,还学习了java中list的实际传递方式。不过还是有点云里雾里的,需要再做一点题来熟悉。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/578928.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c语言中的联合体和枚举

这篇文章总结一下c语言中的联合体和枚举。看看这两个东西到底是什么。大家一起学习。 文章目录 一、联合体1.联合体类型的声明。2.联合体的大小。3.相同成员的结构体和联合体对比4.联合体大小的计算。 二、枚举类型1.枚举类型的声明。2.枚举类型的优点。枚举类型的使用。 一、联…

C++王牌结构hash:哈希表开散列(哈希桶)的实现与应用

目录 一、开散列的概念 1.1开散列与闭散列比较 二、开散列/哈希桶的实现 2.1开散列实现 哈希函数的模板构造 哈希表节点构造 开散列增容 插入数据 2.2代码实现 一、开散列的概念 开散列法又叫链地址法(开链法)&#xff0c;首先对关键码集合用散列函数计算散列地址&…

一文教你如何轻松领取腾讯云优惠券

腾讯云作为国内领先的云计算服务商&#xff0c;为用户提供了丰富的云产品和服务。为了让更多用户享受到腾讯云服务的优质体验&#xff0c;腾讯云推出了各种优惠券&#xff0c;让用户在购买云服务时能够获得更多实惠。本文将为大家详细介绍如何轻松领取腾讯云优惠券&#xff0c;…

智慧公厕,为智慧城市建设注入了新的活力

随着智慧城市的快速发展&#xff0c;公共厕所不再是简单的功能设施&#xff0c;而是成为了提升城市形象、改善民生服务的重要一环。智慧公厕作为新形态的公共厕所&#xff0c;通过精准监测公厕内部的人体活动状态、人体存在状态、空气质量情况、环境变化情况、设施设备运行状态…

使用PopLDdecay软件绘制LD衰减图

前记 PopLDdecay是一款用于进行种群遗传学和关联分析的软件。它可以在全基因组水平上进行基因型数据的相关性和衰减分析&#xff0c;帮助研究人员探索种群间的遗传差异和突变选择的模式。 使用PopLDdecay可以实现以下功能&#xff1a; 遗传距离的计算&#xff1a;可以计算遗…

bugku-web-eval

页面源码 <code><span style"color: #000000"> <span style"color: #0000BB"><?php <br /> </span><span style"color: #007700">include </span><span style"color: #DD0000"&…

37-巩固练习(一)

37-1 if语句等 1、问&#xff1a;输出结果 int main() {int i 0;for (i 0; i < 10; i){if (i 5){printf("%d\n", i);}return 0;} } 答&#xff1a;一直输出5&#xff0c;死循环 解析&#xff1a;i5是赋值语句&#xff0c;不是判断语句&#xff0c;每一次循…

类与对象中C++

加油&#xff01;&#xff01;&#xff01; 文章目录 前言 一、类的6个默认成员函数 ​编辑 二、构造函数 1.概念 三、析构函数 1.概念 2.特性 四、拷贝构造函数 1.概念 2.特征 拷贝构造函数典型调用场景 五、赋值运算符重载 1.运算符重载 2.赋值运算符重载 赋值运算符重载格式…

gitee规范团队 代码提交

1.团队开会规范 使用 插件 &#xff1a; git Commit Message Helper 插件进行代码提交前规范 2.gitee代码仓库断控制&#xff0c;上面只是规范了程序员开发端&#xff1b;但是gitee也要管理控制&#xff1b;正则根据每个公司的不同来进行。

基于Springboot+vue的宠物销售商城网站

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;宠物销售商城当然也不能排除在外。宠物销售商城是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#x…

【目录整理】(五)

​​​​​Git 基础 Git 详细安装教程文章浏览阅读10w次&#xff0c;点赞9.6k次&#xff0c;收藏1.7w次。Git 是个免费的开源分布式版本控制系统&#xff0c;下载地址为git-scm.com 或者 gitforwindows.org&#xff0c;本文介绍 Git-2.40.0-64-bit.exe 版本的安装方法&#x…

力软框架打开新的对话框,点击对话框确认按钮的事件AcceptClick的方法

// 原来在力软框架下&#xff0c;点击哪个确认按钮的时候 top.frames[iframeId].AcceptClick直接用这个方法就可以了 &#xff0c;那个方法是直接返回方法的但是不知道是什么情况。如图二所示。死活就返回了ifram标签不知道是什么原因&#xff0c;就获取不到对话框里边自己定义…