回溯理论基础及leetcode例题
回溯
与递归相辅相成;回溯是递归的副产品,只要有递归就会有回溯。
回溯函数也就是递归函数,指的都是一个函数。
回溯搜索法
纯暴力搜索
解决的问题
组合问题:N个数里面按一定规则找出k个数的集合
切割问题:一个字符串按一定规则有几种切割方式
子集问题:一个N个数的集合里有多少符合条件的子集
排列问题:N个数按一定规则全排列,有几种排列方式(与组合差别,排列有元素顺序)
棋盘问题:N皇后,解数独等等
理解
抽象的不易理解;抽象为图形结构--树形结构
N叉树【树的宽度:集合的大小(for处理);深度:递归的深度(递归处理)】
模板
void backtracking(参数){
if(终止条件){
收集结果;
return;
}
//单层搜索
for(选择:本层集合中元素(树中节点孩子的数量就是集合的大小)){//集合元素集
处理节点;
backtracking(路径,选择列表);//递归函数;
回溯操作; //(12,把2回溯,变13;没有回溯操作就会递归为123)
}
return;
}
递归里面嵌套for循环,for循环里又有递归
leetcode题目
组合
77.组合
for循环嵌套太多层了
树形结构
不能取前面的的:因为组合是无序的,会重复;
每个节点都是一个for循环
回溯三部曲
递归函数参数返回值
确定终止条件
单层递归逻辑
伪代码
全局变量:二维数组res【返回值】
一维数组path【单个结果】
//确定返回值参数
void backtracking(n,k,start){//n集合大小;k需要的子集合大小;start每个取值的开始;
//确定终止条件
if(path.size == k){
res.add(path);
return;
}
//单层递归逻辑
//对于1,234节点
for(i=start,i<=n;i++){
path.push(i);//1
backtracking(n,k,i+1);//遍历剩下的集合234;
path.pop();//回溯过程
}
}
实现
java版本
class Solution {
List<List<Integer>> res = new ArrayList<List<Integer>>();
List<Integer> path = new ArrayList<Integer>();
public List<List<Integer>> combine(int n, int k) {
backtracking(n,k,1);
return res;
}
public void backtracking(int n,int k,int start){
if(path.size() == k){
res.add(new ArrayList<>(path));//容易犯错误
return;
}
for(int i=start;i<=n;i++){//i<=n -(k-path.size()) + 1 会减少运行时间【剪枝操作】
path.add(i);
backtracking(n,k,i+1);
path.remove(path.size()-1);
}
}
}
问题:参考
在链表path里面添加值,然后把path链表添加进res链表中,在做算法题的时候,平时使用res.add(path),结果发现输出打印为空:
在链表path里面添加值,然后把path链表添加进res链表中,在做算法题的时候,平时使用res.add(path),结果发现输出打印为空: | res.add(new ArrayList<>(path))和res.add(path)的区别 |
---|---|
共同点: | 都是向res这个ArrayList中填加了一个名为path的链表 |
不同点: | res.add(new ArrayList(path)):开辟一个独立地址,地址中存放的内容为path链表,后续path的变化不会影响到res |
res.add(path):将res尾部指向了path地址,后续path内容的变化会导致res的变化。 |
优化:剪枝
可以剪枝的地方就在递归中每一层的for循环所选择的起始位置。
如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了。
优化过程如下:
已经选择的元素个数:path.size();
所需需要的元素个数为: k - path.size();
列表中剩余元素(n-i) >= 所需需要的元素个数(k - path.size())
在集合n中至多要从该起始位置 : i <= n - (k - path.size()) + 1,开始遍历
分割
131. 分割回文串
树形结构
回溯三部曲
递归函数参数返回值
确定终止条件
单层递归逻辑
伪代码
收集结果路径
void backtracking(string s,startIndex){
//终止条件
//即切割线是终止条件
if(startIndex >= s.length()){
res.add(path);
return;
}
//单层递归逻辑
//切割字串范围:(startIndex,i]
for(i=startIndex;i< s.length();i++){
if(isPalindrome(s,startIndex,i)){
path.add(子串);
}else continue;
backtracking(s,i+1);
path.remove(path.size()-1);
}
}
实现
java版本
class Solution {
List<List<String>> result = new ArrayList<List<String>>();
List<String> path = new ArrayList<String>();
public List<List<String>> partition(String s) {
backtracking(s,0);
return result;
}
public void backtracking(String s,int startIndex){
if(startIndex >= s.length()){
result.add(new ArrayList<String>(path));
return;
}
for(int i=startIndex;i<s.length();i++){
String sub = s.substring(startIndex,i+1);
if(isPalindrome(sub)){
path.add(sub);
}else {continue;}
backtracking(s,i+1);
path.remove(path.size()-1);
}
}
public boolean isPalindrome(String s){
int left = 0;
int right = s.length()-1;
while(left<right){
if(s.charAt(left) != s.charAt(right)){
return false;
}
left++;
right--;
}
return true;
}
}
子集问题
78. 子集
树形结构
收获结果的时候:在每个节点收获结果
组合和分割问题都是在叶子节点里取结果;
伪代码
void backtracking(nums,stratIndex){
result.add(path);
if(stratIndex >= path.size()) return;
for(int i=startIndex;i<nums.length;i++){
path.add(nums[i]);
backtracking(nums,i+1);
path.remove(path.size()-1);
}
}
实现
class Solution {
List<List<Integer>> list = new ArrayList<List<Integer>>();
List<Integer> path= new ArrayList<Integer>();
public List<List<Integer>> subsets(int[] nums) {
backtracking(nums,0);
return list;
}
public void backtracking(int[] nums,int stratIndex){
list.add(new ArrayList<Integer>(path));
if(stratIndex>=nums.length){
return;
}
for(int i=stratIndex;i<nums.length;i++){
path.add(nums[i]);
backtracking(nums,i+1);
path.remove(path.size()-1);
}
}
}
排列
46.全排列
树形结构
伪代码:
void backtracking(nums,used){
if(path.size() == nums.length){
res.add(path);
return;
}
for(i=0;i<nums.length;i++){
if(used[i] == true) continue;
used[i] = true;
path.add(nums[i]);
backtracking(nums,used);
used[i] = false;
path.remove(path.size()-1);
}
}
实现
class Solution {
List<List<Integer>> list = new ArrayList<List<Integer>>();
List<Integer> path = new ArrayList<Integer>();
public List<List<Integer>> permute(int[] nums) {
boolean[] used = new boolean[nums.length];
backtracking(nums,used);
return list;
}
public void backtracking(int[] nums,boolean[] used){
if(path.size() >= nums.length){
list.add(new ArrayList<>(path));
return;
}
for(int i=0;i<nums.length;i++){
if(used[i] == true) continue;
path.add(nums[i]);
used[i] = true;
backtracking(nums,used);
path.remove(path.size()-1);
used[i] = false;
}
}
}
回溯理论基础及leetcode例题的更多相关文章
- 滑动窗口法——Leetcode例题
滑动窗口法--Leetcode例题(连更未完结) 1. 方法简介 滑动窗口法可以理解为一种特殊的双指针法,通常用来解决数组和字符串连续几个元素满足特殊性质问题(对于字符串来说就是子串).滑动窗口法的显 ...
- 【题解】【排列组合】【回溯】【Leetcode】Generate Parentheses
Given n pairs of parentheses, write a function to generate all combinations of well-formed parenthes ...
- 【题解】【排列组合】【回溯】【Leetcode】Gray Code
The gray code is a binary numeral system where two successive values differ in only one bit. Given a ...
- 【题解】【矩阵】【回溯】【Leetcode】Unique Paths II
A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The ...
- 回溯法和DFS leetcode Combination Sum
代码: 个人浅薄的认为DFS就是回溯法中的一种,一般想到用DFS我们脑中一般都有一颗解法树,然后去按照深度优先搜索去寻找解.而分支界限法则不算是回溯,无论其是采用队列形式的还是优先队列形式的分支界限法 ...
- 【题解】【矩阵】【回溯】【Leetcode】Rotate Image
You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwise). ...
- 由Leetcode详解算法 之 动态规划(DP)
因为最近一段时间接触了一些Leetcode上的题目,发现许多题目的解题思路相似,从中其实可以了解某类算法的一些应用场景. 这个随笔系列就是我尝试的分析总结,希望也能给大家一些启发. 动态规划的基本概念 ...
- Poj 1321 棋盘问题 【回溯、类N皇后】
id=1321" target="_blank">棋盘问题 Time Limit: 1000MS Memory Limit: 10000K Total Subm ...
- [LeetCode]sum合集
LeetCode很喜欢sum,里面sum题一堆. 1.Two Sum Given an array of integers, return indices of the two numbers suc ...
- 8皇后问题SQL求解(回溯算法)
问题 八皇后问题是一个古老而著名的问题,是回溯算法的典型例题.该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一 ...
随机推荐
- 👋 和我一起学【Three.js】「初级篇」:0. 总论
「和我一起学 XXX」是我 2023 年的一个新企划,目的是向读者(也包括未来的自己)介绍我正在学习的某项新技术.文章会通过长期反复迭代的方式保持其内容的新鲜度.文章有较大内容更新时,会在文章开头进行 ...
- 一招教你 Notion 文章导出到公众号
Notion是一个功能强大的笔记应用程序,有许多优点,包括: 用户友好的界面 跨平台支持 可以结构化组织笔记 多人协作 可以添加多种类型的媒体文件 可以添加评论和任务 这些优点使Notion成为一个广 ...
- 如何在 Apinto 实现 HTTP 与gRPC 的协议转换 (上)
什么是 gRPC 像gRPC是由google开发的一个高性能.通用的开源 RPC 框架,主要面向移动应用开发且基于HTTP/2协议标准而设计,同时支持大多数流行的编程语言. gRPC基于 HTTP/2 ...
- webgl 系列 —— 绘制猫
其他章节请看: webgl 系列 绘制猫 上文我们了解了如何绘制渐变彩色三角形,明白了图形装配.光栅化,以及片元着色器计算片元的颜色. 现在如果让你绘制如下一只猫.难道绘制很多三角形,然后指定它们的颜 ...
- 【微信网页授权】SpringBoot+uniapp实现网页授权获取用户基本信息
前言 缘由 起因于本狗上一个项目本打算采用微信公众号网页授权登录做用户鉴权,但最终因公众号是未认证的订阅号,无权限获取用户信息,所以改变思路,采用登录注册方式实现用户区分.但在开发中,学习了微信网页授 ...
- 全网最详细中英文ChatGPT-GPT-4示例文档-从0到1快速入门python代码解释应用——官网推荐的48种最佳应用场景(附python/node.js/curl命令源代码,小白也能学)
目录 Introduce 简介 setting 设置 Prompt 提示 Sample response 回复样本 API request 接口请求 python接口请求示例 node.js接口请求示 ...
- 制作一个同时具有PE和Windows原版安装方式的U盘
这个方法可能很多人已经制作成功过了,但是呢,也有些人不会的,也可能没想到过,那就是让Win PE与Windows原版安装包在一个U盘里面同时共存. 需要用到的软件有这几样:DiskGenius.Gim ...
- Redis系列12:Redis 的事务机制
Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 Redis系列3:高可用之主从架构 Redis系列4:高可用之Sentinel(哨兵模式) Redis系列5: ...
- 时隔十年,QQ更新了Linux版本
昨天1024程序员节,QQ悄悄地更新了QQ for Linux,也许是给各位一个惊喜吧. 官网及其的简陋.和一个Word文档似的. 十年一更,有网友称,瞬间回到QQ2006,确实界面功能有些落后,相信 ...
- [大数据]sqoop安装与运用
1 文由 项目使用场景:OLTP Oracle 数据导入到 OLAP HIVE 2 Sqoop简述 Apache Sqoop(TM) 是一款开源的ETL工具,设计用于在 Apache Hadoop和结 ...