算法笔记(java)——回溯篇

回溯算法解决问题最有规律性,借用一下卡哥的图:
在这里插入图片描述

只要遇到上述问题就可以考虑使用回溯,回溯法的效率并不高,是一种暴力解法,其代码是嵌套在for循环中的递归,用来解决暴力算法解决不了的问题,即可以通过回溯控制递归的层数,递归后可以进行回溯操作,这样下一次循环就不会收到上一次的影响。解决回溯问题的关键就在于清楚整个回溯递归过程,毕竟是嵌套在for循环中的递归,最好的办法就是把所有情况画成一个树,这样就比较清晰了。

递归通用模版和常用API

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

常用API

  • temp常用LinkedList,因为可以在回溯的时候快速删除最后一个元素,添加使用add,删除使用removeLast
  • 将temp添加进result时,要new一个新的arrayList将temp传入构造器,因为temp是全局共享的,如果不new那么result里没有值
  • 如果需要下一层递归指向下一个数,那么要加参数startIndex,如果是排列问题等,每次从头开始,就不需要了

回溯简单示例

力扣题目:

第77题. 组合

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

示例: 输入: n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]

暴力for循环是没法解决本题的,因为不知道要写多少层,所以使用回溯法。
本题图解:
在这里插入图片描述
本题代码:

class Solution {List<List<Integer>> result = new ArrayList<>();LinkedList<Integer> temp = 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(temp.size() == k){result.add(new ArrayList<Integer>(temp));return;}for(int i=startIndex;i<=n-(k-temp.size())+1;i++){temp.add(i);backTracking(n,k,i+1);temp.removeLast(); //  回溯}}
}

去重问题

去重是使用回溯算法时遇到的最重要的问题,卡哥将去重分为了树枝去重以及数层去重,就是for循环的去重和各层递归的去重,一个横向一个纵向。

最常用的去重思路:
先对原数组排序,使用used数组,对横向for循环去重,对纵向递归不去重。

力扣题目:

40. 组合总和 II

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

注意:解集不能包含重复的组合。

示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

本题图示:
在这里插入图片描述
可以看到只要排序好,进行横向去重就行了。used数组的作用就是去重的时候不要误删纵向情况,因为used数组有回溯操作,下一次for循环的used[i-1]是false了已经,而下一层递归是true,以此为条件进行判断。

class Solution {// 去重,去重横向的,纵向递归的不去重,要用used[i-1]防止纵向的被去重的时候误删List<List<Integer>> result = new ArrayList<>();LinkedList<Integer> temp = new LinkedList<>();public List<List<Integer>> combinationSum2(int[] candidates, int target) {if(candidates == null && candidates.length == 0){return null;}Arrays.sort(candidates);boolean[] used = new boolean[candidates.length];backtracking(candidates,target,0,0,used);return result;}public void backtracking(int[] candidates,int target,int sum,int startIndex,boolean[] used){if(sum == target){result.add(new ArrayList<>(temp));return;}for(int i=startIndex;i<candidates.length && sum+candidates[i]<=target;i++){if(i>0 && candidates[i] == candidates[i-1] && used[i-1] == false){continue;}sum += candidates[i];temp.add(candidates[i]);used[i] = true;backtracking(candidates,target,sum,i+1,used);used[i] = false;temp.removeLast();sum -= candidates[i];}}
}

还有用used数组去重不了的情况
Set去重
力扣题目:

491. 递增子序列

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。

数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

示例 1:

输入:nums = [4,6,7,7]
输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]

这道题显然是不能用used数组的,因为没法排序,排序后就判断不了递增子序列了。使用hashset或者数组进行去重

class Solution {// 不能排序的去重,使用hashsetList<List<Integer>> result = new ArrayList<>();LinkedList<Integer> temp = new LinkedList<>();public List<List<Integer>> findSubsequences(int[] nums) {backTracking(nums,0);return result;}public void backTracking(int[] nums,int startIndex){if(judge(temp)){result.add(new ArrayList<>(temp));}HashSet<Integer> set = new HashSet<>();for(int i= startIndex;i<nums.length;i++){if(set.contains(nums[i])){continue;}set.add(nums[i]);temp.add(nums[i]); backTracking(nums,i+1);temp.removeLast();}}public boolean judge(List<Integer> list){if(list.size()<2){return false;}for(int i=0,j=0;j<list.size()-1;i++){j=i+1;if(list.get(i)>list.get(j)){return false;}}return true;}
}

每层递归都有自己的hastSet,然后可以对横向for循环去重,因为每一层递归set都不一样,所以不会影响到纵向递归。使用数组同理,和set差不多。

其他问题

排列和组合的区别:

排列是每次递归都是从头开始的:
力扣题目:

46. 全排列

在这里插入图片描述

使用used数组是来判断这个元素有没有在上层递归使用过,毕竟每次都是从0开始

class Solution {List<List<Integer>> result = new ArrayList<>();LinkedList<Integer> temp = new LinkedList<>();public List<List<Integer>> permute(int[] nums) {boolean[] used =new boolean[nums.length];backTracking(nums,used);return result;}public void backTracking(int[] nums,boolean[] used){if(temp.size() == nums.length){result.add(new ArrayList<>(temp));return;}for(int i=0;i<nums.length;i++){if(used[i] == true){continue;}temp.add(nums[i]);used[i] = true;backTracking(nums,used);used[i] = false;temp.removeLast();}}
}

78.子集和90.子集II属于子集问题,这类问题的特点就是要采集树上每一个出现过的元素,不难,去重逻辑也是上面那样。

还有一些拼接字符串的,需要用StringBuilder和一些stringApi的题目:
131.分割回文串和93.复原IP地址 不算难但是比较恶心。

比较难的就是:
51. N皇后
需要遍历矩阵,但是只需要一个for循环,判定条件比较多
52. 解数独
需要双层循环,判定条件也比较复杂

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

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

相关文章

Tensorflow无人车使用移动端的SSD(单发多框检测)来识别物体及Graph的认识

环境是树莓派3B&#xff0c;当然这里安装tensorflow并不是一定要在树莓派环境&#xff0c;只需要是ARM架构就行&#xff0c;也就是目前市场上绝大部分的嵌入式系统都是用这套精简指令集。 在电脑端的检测&#xff0c;有兴趣的可以查阅SSD(Single Shot MultiBox Detector)系列&a…

19 QListWidget控件

Tips: 对于列表式数据可以使用QStringList进行左移一块输入。 代码&#xff1a; //listWidget使用 // QListWidgetItem * item new QListWidgetItem("锄禾日当午"); // QListWidgetItem * item2 new QListWidgetItem("汗滴禾下土"); // ui->…

十、正则表达式详解:掌握强大的文本处理工具(二)

文章目录 &#x1f340;多字符匹配&#x1f340;匹配规则的代替&#x1f340;特殊的匹配&#x1f340;特殊的匹配plus&#x1f340;总结 &#x1f340;多字符匹配 星号&#xff08;*&#xff09;&#xff1a;匹配0个或者多个字符 import retext 111-222-333 result re.matc…

苹果的Apple GPT要来了?

据外媒消息&#xff0c;苹果正在内部开发类 ChatGPT 的产品&#xff0c;与微软、OpenAI、谷歌、Meta 等科技巨头在生成式 AI 赛道展开竞争。该消息使得苹果股价上涨了 2%。据苹果工程师透露&#xff0c;苹果在内部构建了代号为“Ajax”的大语言模型开发框架&#xff0c;并构建了…

Unity自定义后处理——Bloom效果

大家好&#xff0c;我是阿赵。   继续介绍屏幕后处理效果&#xff0c;这一期讲一下Bloom效果。 一、Bloom效果介绍 还是拿这个模型作为背景。 Bloom效果&#xff0c;就是一种全屏泛光的效果&#xff0c;让模型和特效有一种真的在发光的感觉。 根据参数不一样&#xff0c;可…

Packet Tracer – 实施静态 NAT 和动态 NAT

Packet Tracer – 实施静态 NAT 和动态 NAT 拓扑图 目标 第 1 部分&#xff1a;利用 PAT 配置动态 NAT 第 2 部分&#xff1a;配置静态 NAT 第 3 部分&#xff1a;验证 NAT 实施 第 1 部分&#xff1a; 利用 PAT 配置动态 NAT 步骤 1&#xff1a; 配置允许用于 NAT …

【基于CentOS 7 的iscsi服务】

目录 一、概述 1.简述 2.作用 3. iscsi 4.相关名称 二、使用步骤 - 构建iscsi服务 1.使用targetcli工具进入到iscsi服务器端管理界面 2.实现步骤 2.1 服务器端 2.2 客户端 2.2.1 安装软件 2.2.2 在认证文件中生成iqn编号 2.2.3 开启客户端服务 2.2.4 查找可用的i…

AJAX-day03-AJAX进阶

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 同步代码和异步代码 回调函数地狱 Promise - 链式调用 Promise 链式应用 async函数和await async函…

Stable Diffusion入门笔记(自用)

学习视频&#xff1a;20分钟搞懂Prompt与参数设置&#xff0c;你的AI绘画“咒语”学明白了吗&#xff1f; | 零基础入门Stable Diffusion保姆级新手教程 | Prompt关键词教学_哔哩哔哩_bilibili 1.图片提示词模板 2.权重&#xff08;提示词&#xff09; 无数字 (flower)//花的…

MQTT网关 5G物联网网关 PLC控制工业网关

MQTT网关&#xff0c;两个以上的节点之间通信的新型网关&#xff0c;网络节点之间通过互连来实现双向通信。支持PLC协议转MQTT&#xff0c;实现plc数据采集上云&#xff0c;物联网云平台对接&#xff0c;广泛应用于工业自动化plc远程监测控制。 计讯物联5G MQTT物联网网关TG463…

如何解决 Git 合并冲突

在遇到合并冲突时&#xff0c;请不要惊慌。通过一些娴熟的技巧协商&#xff0c;你可以解决任何冲突。 假设你和我正在共同编辑同一个名称为 index.html 的文件。我对文件进行了修改&#xff0c;进行了提交&#xff0c;并将更改推送到 Git 远程仓库。你也对同一个文件进行了修改…

酷雷曼无人机技能培训考试圆满举办

2023年7月18日、19日&#xff0c;以“向云端起航&#xff0c;让技术落地”为主题的酷雷曼无人机技能提升培训会在酷雷曼北京运营中心隆重举行&#xff0c;来自全国各地的众多合作商参加了本次培训&#xff0c;通过系统、全面的学习成功取得了专业无人机飞行员执照&#xff0c;为…

BEVDet 论文解读

BEVDet: High-Performance Multi-Camera 3D Object Detection in Bird-Eye-View 作者单位 PhiGent Robotics 目的 2D 的视觉感知在过去的几年里有了急速的发展&#xff0c;涌现出一些优秀的范式工作&#xff0c;这些工作有较高的性能&#xff0c;可扩展性&#xff0c;以及多…

【数学建模】--典型相关分析

典型相关分析&#xff08;Canonical Correlation analysis&#xff09;研究两组变量&#xff08;每组变量中都可能有多个指标&#xff09;之间相关关系的一种多元统计方法。它能够揭示出两组变量之间的内在联系。 例子&#xff1a; 典型相关分析定义&#xff1a; 列题分析&…

OpenCV自带的HAAR级联分类器对脸部(人脸、猫脸等)的检测识别

在计算机视觉领域&#xff0c;检测人脸等是一种很常见且非常重要的应用&#xff0c;我们可以先通过开放计算机视觉库OpenCV来熟悉这个人脸识别领域。另外OpenCV关于颜色的识别&#xff0c;可以查阅&#xff1a;OpenCV的HSV颜色空间在无人车中颜色识别的应用HSV颜色识别的跟踪实…

苹果账号被禁用怎么办

转载&#xff1a;苹果账号被禁用怎么办 目录 禁用的原因 解除Apple ID禁用 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UKQ1ILhC-1689932607373)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw)]​编辑 …

fiddler抓取,Android真机测试

1.配置Fiddler抓取并解密HTTPS包 Fiddler默认是不抓取HTTPS包的&#xff0c;需要进行相应的配置。 打开Fiddler&#xff0c;选择“Tools->Fiddler Options...” 2.在弹出的对话框中选择“HTTPS”选项卡&#xff1a; 3.勾选“Capture HTTPS CONNECTs”&#xff0c;接着勾选…

第三天 运维高级 MySQL主从复制

1.理解MySQL主从复制原理 1、master&#xff08;binlog dump thread&#xff09;主要负责Master库中有数据更新的时候&#xff0c;会按照binlog格式&#xff0c;将更新的事件类型写入到主库的binlog文件中。 2、I/O thread线程在Slave中创建&#xff0c;该线程用于请求Master&…

uniapp 微信小程序 Picker下拉列表数据回显问题

效果图&#xff1a; 1、template <template><view class"items select-box"><view class"items-text">品牌型号</view><picker change"bindBrandType" :value"brandIndex" :range"brandList"…

HTTP 什么样的响应才会被缓存

下面来讨论什么样的响应会被缓存&#xff0c;以及使用好已经缓存好的条件是什么。 缓存分为两步&#xff0c;首先将响应缓存下来&#xff0c;第二步将要发起一个请求的时候检查当前缓存是否可以使用缓存了的响应。 (1) 请求方法可以被缓存理解&#xff08;不只于 GET 方法&…