DFS中的回溯法(纯暴力穷举)
首先回溯法是深度搜索(DFS)的一种,即把所有可能穷举,根据条件筛选出符合条件的路径。
回溯法模板格式
dfs(...){//根据递归终止条件进行筛选
if(符合需要的条件){存储合理路径
return ...;
}
//对可能路径进行遍历
for(int i=起始条件;i<极限边界;i++){向路径便令中添加元素
//进行下一轮搜索
def(...);
//深度优化的回头
...removeLast();
}
return ...;
}
下面举一个leetCode上的题目:
给出正整数n,k,求出1,2,3,4…n;求出所有含k个数字且无重复的全部结果。(题目大致是这样的)
用回溯法的解决如下:
public class Backtrack {private static Backtrack test;public static void main(String[] args) {int k = 3;int n = 5;shen = new Backtrack2();test.cobine(n, k);}public List<List<Integer>> cobine(int n, int k) {List<List<Integer>> res = new ArrayList<>();if (k <= 0 || n < k) {return res;}
// 创建一个list记录搜索路径List<Integer> path = new ArrayList<>();dfs(n, k, 1, path, res);return res;}public List<List<Integer>> dfs(int n, int k, int start, List<Integer> path, List<List<Integer>> res) {// 递归终止条件是:path的长度为k
// System.out.println(path);思路不清晰的话可以打印出每条路径path看下过程对理解很有帮助if (path.size() == k) {res.add(new ArrayList<Integer>(path));return res;}
// 遍历可能的搜索起点for (int i = start; i <= n; i++) {// 向路径变量中添加一个数字path.add(i);
// 下一轮搜索,设置的搜索起点要加1,因为组合数里不允许出现重复的元素dfs(n, k, i + 1, path, res);
// 重点理解这里,深度优化遍历有回头的过程,因此递归之前做了什么,递归之后就要做相同的逆操作path.remove(path.size() - 1);}return res;}
}
上面的题目是要求不能有重复元素的,下面给出一道可以有重复题目:
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的数字可以无限制重复被选取
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
一个简单的java解题代码如下:
这里假设target=7,candidate={2,3,6,7}
public class CombinationSum {public static void main(String[] args) {int target = 7;int[] candidates = {2, 3, 6, 7};CombinationSum shen = new CombinationSum();System.out.println("结果是:" + shen.combinationSum(candidates, target).toString());}public List<List<Integer>> combinationSum(int[] candidates, int target) {// 判断cambinationSum是否为空,若是空值接返回不需要往下算了List<List<Integer>> res = new ArrayList<>();if (candidates == null || candidates.length == 0) {return null;}
// 创建路径记录变量List<Integer> path = new ArrayList<>();dfs(0,path,candidates,target,res);return res;}public void dfs(int start, List<Integer> path, int[] candidates, int target,List<List<Integer>> res) {// 根据终止条件这里先求出每个路径的和再来判断,容易理解,但是代码会比较臃肿int sum = 0;for (int i = 0; i < path.size(); i++) {sum += path.get(i);}System.out.println(path);//思路不清晰的话可以打印出每条路径path看下过程对理解很有帮助
// 下面的这两个if的判断条件非常重要,DFS里面需要思考的就是这个判断条件部分,其他部分的格式几乎是一样的if (sum > target) {return ;}if (sum == target) {res.add(new ArrayList<Integer>(path));return ;}
// 遍历可能的搜索起点for (int i = start; i < candidates.length; i++) {// 想路径变量中添加元素path.add(candidates[i]);
// 这里需要注意一下第一个值:i, 元素可以重复的话搜索起点为:i;元素不可重复的话搜索起点为:i+1dfs( i, path, candidates, target, res);
// 深度优化搜索的回头过程,这里使用的是List作为搜索路径path,也可以使用其他容器path.remove(path.size()-1 );}}
}
上面两种做法只是完成了最基本的功能并没有进行优化,比较适合像我一样刚接触回溯和dfsd的小白,在这基础上可以进行剪枝,减去不合理路径,使得运算效率更快,下面是对借鉴的另一种解法:
public class Solution {public List<List<Integer>> combinationSum(int[] candidates, int target) {int len = candidates.length;List<List<Integer>> res = new ArrayList<>();if (len == 0) {return res;}Deque<Integer> path = new ArrayDeque<>();dfs(candidates, 0, len, target, path, res);return res;}/*** @param candidates 候选数组* @param begin 搜索起点* @param len 冗余变量,是 candidates 里的属性,可以不传* @param target 每减去一个元素,目标值变小* @param path 从根结点到叶子结点的路径,是一个栈* @param res 结果集列表*/private void dfs(int[] candidates, int begin, int len, int target, Deque<Integer> path, List<List<Integer>> res) {// target 为负数和 0 的时候不再产生新的孩子结点if (target < 0) {return;}if (target == 0) {res.add(new ArrayList<>(path));return;}// 重点理解这里从 begin 开始搜索的语意for (int i = begin; i < len; i++) {path.addLast(candidates[i]);// 注意:由于每一个元素可以重复使用,下一轮搜索的起点依然是 i,这里非常容易弄错dfs(candidates, i, len, target - candidates[i], path, res);// 状态重置path.removeLast();}}
}
这是leetCode比较经典的解法,使用了剪枝,也用了Deque容器,进入链接看具体的讲解:
链接:https://leetcode-cn.com/problems/combination-sum/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-m-2/
DFS中的回溯法(纯暴力穷举)相关推荐
- C++ 求最大公约数 更相减损法 欧几里得算法 暴力穷举法
两个数的最大公约数是指能同时被他们整除的最大正整数. 两个数的最大公约数等于它们中 较小的数 和 两数之差 的最大公约数. 252和105的最大公约数是21(252 = 21 × 12:105 = 2 ...
- java中穷举法排序_java穷举法小案例
最近几天伤病没有更新 今天好点 看了一下基础的算法 现在简单更新一下 --穷举法 一.甲 .乙.丙 三位球迷分别预测进入半决赛的四队A.B.C.D的名次如下: 甲:A 第一名 .B 第二名 乙:C ...
- c语言变量相等问题穷举法,C语言穷举法经典例题.ppt
<C语言穷举法经典例题.ppt>由会员分享,可在线阅读,更多相关<C语言穷举法经典例题.ppt(18页珍藏版)>请在人人文库网上搜索. 1.枚举法(穷举法),"笨人之 ...
- 百鸡问题用计算机什么法解决,《穷举法解决问题》教学设计
一.教学目标 1.知识与技能 ⑴了解穷举法的基本概念及用穷举法设计算法的基本过程. ⑵分析建立正确的数学模型,归纳穷举法穷举技巧. ⑶能够根据具体问题的要求,使用穷举法设计算法,编写程序求解问题. 2 ...
- python穷举法列举_穷举法应用举例.doc
无 止 境 穷举法应用举例 在数学问题中, 有一些需要计算总数或种类的趣题, 因其数量关系比较隐蔽, 很难找到"正统"的方式解答,让人感到无从下手.对此,我们可以先初步估计 其数目 ...
- 通过selenium,暴力穷举身份证号登陆某网站
偶然发现小学女神在某大学读研,想联系一波.十多年没有联系,怎么办?发现研究生录取查询只用身份证号+姓名+验证码,身份证号学校在某些文件公布了14位,剩下四位要穷举,身份证最后一位校验位,倒数第二位性别 ...
- dfs中return回溯问题
题目: 从1到n中选k个数进行排列 首先我们看这段代码: #include <iostream> using namespace std; int n, k; const int N = ...
- 部分和(dfs深搜回溯法)
问题描述 给定整数序列a1,a2,.,an,判断是否可以从中选出若干数,使它们的和恰好为k, 1<=n<=20 -10^8<=ai<=10^8 -10^8<=k<= ...
- 【LeetCode 剑指offer刷题】回溯法与暴力枚举法题6:Number of Islands
[LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) Number of Islands Given a 2d grid map of '1's (land) and ' ...
最新文章
- MySQL 5.5 的COMPRESSED INNODB 表
- 设计模式 -(5)装饰模式(结构型)
- NYOJ 737---石子归并(GarsiaWachs算法)
- mysql下载备份数据库命令行,如何从MariaDB数据库备份和还原命令行
- VC6启用运行时类型识别 (RTTI)
- 数据结构 练习21-trie的原理分析和应用
- 继承AppCompatActivity的Activity无法隐藏标题栏
- 瑞友客户端无法建立跟远程计算机的连接,瑞友天翼终端错误信息的原因以及解决方法大全.doc...
- IDEA系列(六)一This file is indented with tabs instead of 4 space
- Spring Boot 概述、初始化器、spring-boot-maven-plugin 插件简化部署、starter 自动配置原理
- SpringMVC学习指南【笔记4】数据绑定、表单标签库、转换器、格式化、验证器
- 华为服务器怎么装win7系统教程视频教程,华为交换机配置教程|华为交换机配置视频教程完整版...
- jQuery 文档碎片处理
- PCB屏蔽罩图纸制作
- PMBOK 项目管理 九大知识领域和五大流程
- 微信小程序自定义函数返回值
- 网易七鱼客服 发起客服-触发两条会话
- damon ps2 android,DamonPS2模拟器
- HTML 樱花飘落界面效果
- excel一个表格分成多个的简单方法
热门文章
- 速轩三维 - 白光/蓝光/拍照式三维扫描仪
- 如何安装tree命令
- 软件测试 | 测试开发 | 探究 PHP_CodeSniffer 的代码静态分析原理
- php 在线选座,基于jquery实现在线选座订座之影院篇
- 2017最新整理python全栈工程师系统培训之路精品课程(全套)
- python_4.loc()和iloc()函数
- 从键盘输入整数n,输出n以内所有质数。
- 如何反编译pyc文件查看源代码
- java创建画板_Java版画板的实现方法
- easyui部分组件使用经验