文章目录

  • 系列文章目录
  • 前言
  • 题录
    • 131. 分割回文串
    • 93. 复原 IP 地址
    • 78. 子集
    • 90. 子集 II
    • 46. 全排列
    • 47. 全排列 II
    • 491. 递增子序列

系列文章目录

一、 数组类型解题方法一:二分法
二、数组类型解题方法二:双指针法
三、数组类型解题方法三:滑动窗口
四、数组类型解题方法四:模拟
五、链表篇之链表的基础操作和经典题目
六、哈希表篇之经典题目
七、字符串篇之经典题目
八、字符串篇之 KMP
九、解题方法:双指针
十、栈与队列篇之经典题目
十 一、栈与队列篇之 top-K 问题
十 二、二叉树篇之二叉树的前中后序遍历
十 三、二叉树篇之二叉树的层序遍历及相关题目
十 四、二叉树篇之二叉树的属性相关题目
十 五、 二叉树篇之二叉树的修改与构造
十 六、 二叉树篇之二叉搜索树的属性
十 七、二叉树篇之公共祖先问题
十 八、二叉树篇之二叉搜索树的修改与构造
十 九、回溯算法篇之组合问题
更新中 …


前言

刷题路线来自 :代码随想录
切割问题: 一个字符串按一定规则有几种切割方式
子集问题: 一个N个数的集合里有多少符合条件的子集
排列问题: N个数按一定规则全排列,有几种排列方式

题录

131. 分割回文串

Leetcode 链接
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。回文串 是正着读和反着读都一样的字符串。

题解:

  1. 递归参数:可以传入 s,然后传入下层递归开始的下标,然后在下层分割字符串,也可以将字符串分割好作为参数,这里选择后者
  2. 收集结果:s 字符串无法再分割,即长度为 0 时(同结束条件)
  3. 剪枝:分割的部分子串不是回文串,continue 进行下次分割
class Solution {List<List<String>> res = new ArrayList<>();List<String> list = new ArrayList<>();public List<List<String>> partition(String s) {backtracking(s);return res;}public void backtracking(String s) {if (s.length() == 0) {res.add(new ArrayList<>(list));return;}// s 为没有分割过的子串,从头分割for (int i = 1; i <= s.length(); i++) {// 分割部分不是回文串if (!isE(s, 0, i)) continue;list.add(s.substring(0, i));// s.substring(i, s.length()):下层递归分割backtracking(s.substring(i, s.length()));// 回溯list.remove(list.size() - 1);}}// 判断回文串public boolean isE(String s, int l, int r) {r--;while (l < r) {if (s.charAt(l) != s.charAt(r)) {return false;}l++;r--;}return true;}
}

93. 复原 IP 地址

Leetcode 链接

题解: 相比上一题,细节繁多

  1. 回溯对象:StringBuilder 拼接 IP ,拼接前记录下长度,回溯时作为删除末尾子串的下标起始位置
  2. 收集结果:刚好分割为 4 个整数,并且字符串刚好分割完
  3. 返回列表:接下来要分割是子串 s,conut 记录分割的整数个数
  4. 结束条件/剪枝:分割的整数大于 255、前导有 0、分割的整数个数大于 4
class Solution {List<String> res = new ArrayList<>();StringBuilder sb = new StringBuilder();public List<String> restoreIpAddresses(String s) {backtracking(s, 0);return res;}public void backtracking(String s, int count) {if (s.length() == 0 && count == 4) {// 刚好分割为 4 个整数,删除拼接时的'.',添加到返回列表sb.deleteCharAt(sb.length() - 1);res.add(new String(sb));return;}for (int i = 1; i <= s.length() && (count < 4); i++) {int num = Integer.valueOf(s.substring(0, i));// 结束条件,还有一个放在了for 循环的判断中if ((i > 1 && s.charAt(0) == '0') || num > 255) {return;}// 记录拼接前下标用来回溯int idx = sb.length();// 拼接sb.append(num).append('.');backtracking(s.substring(i, s.length()), count + 1);// 回溯sb.delete(idx, sb.length());}}
}

78. 子集

Leetcode 链接
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。


题解:

  1. 回溯对象:路径
  2. 收集结果:收集路径上的所有结果,注意还有一个额外的空集
  3. 结束条件:自然结束,因为套搜索到所有结果
  4. 参数列表:每层递归数组的起始位置
class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();public List<List<Integer>> subsets(int[] nums) {res.add(path);backtracking(nums, 0);return res;}public void backtracking(int[] nums, int start) {for (int i = start; i < nums.length; i++) {// 收集路径上的所有结果path.add(nums[i]);res.add(new ArrayList<>(path));// 是 i + 1, 不是 start + 1backtracking(nums, i + 1);// 回溯path.remove(path.size() - 1);}}
}

90. 子集 II

Leetcode 链接
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

题解: 相比上题,需要增加去重操作

  1. 回溯对象:路径
  2. 收集结果:同上题收集路径上所有结果
  3. 结束条件/剪枝:自然结束
  4. 去重:排序后,同层第一次出现的数不用去重,连续出现的数除第一个外全部 continue 跳过
class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();public List<List<Integer>> subsetsWithDup(int[] nums) {res.add(path);Arrays.sort(nums);backtracking(nums, 0);return res;}public void backtracking(int[] nums, int start) {for(int i = start; i < nums.length; i++) {if (i > start && nums[i] == nums[i - 1]) {// 同层不是第一次出现continue;}path.add(nums[i]);res.add(new ArrayList<>(path));backtracking(nums, i + 1);path.remove(path.size() - 1);}}
}

46. 全排列

Leetcode 链接
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

题解:

  1. 回溯对象:路径,boolean[ ] used
  2. 收集结果:路径长度等于 数组长度 (同结束条件)
  3. 递归参数:因为全排列每层递归从头开始遍历,只需跳过已经过的数,无需 startIndex
  4. 去重操作:每一层递归可用的数都在减少,上题去重只需一个判断,而这里去重的数太多,所以要使用 set 来记录,当然我们也可以使用数组 boolean[ ] used 当遇到已经使用过的数,continue 跳过
class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();boolean[] used;public List<List<Integer>> permute(int[] nums) {used = new boolean[nums.length];backtracking(nums);return res;}public void backtracking(int[] nums) {if (path.size() == nums.length) {// 长度判断,收集结果res.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);// 回溯path.remove(path.size() - 1);used[i] = false;}}}

47. 全排列 II

Leetcode 链接
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列

题解:

  1. 回溯对象:路径,boolean[ ] used
  2. 收集结果:路径长度等于 数组长度 (同结束条件)
  3. 递归参数:因为全排列每层递归从头开始遍历,只需跳过已经过的数,无需 startIndex
  4. 去重操作:
    1.每一层递归可用的数都在减少,上题去重只需一个判断,而这里去重的数太多,所以要使用 set 来记录,当然我们也可以使用数组 boolean[ ] used 当遇到已经使用过的数,continue 跳过
    2.层去重,同子集二,先排序再判断是否当前层第一次出现

哈希去重:

class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();boolean[] used;public List<List<Integer>> permuteUnique(int[] nums) {used = new boolean[nums.length];Arrays.sort(nums);backtracking(nums);return res;}public void backtracking(int[] nums) {if (path.size() == nums.length) {res.add(new ArrayList<>(path));return;}for (int i = 0; i < nums.length; i++) {if (used[i] == true) {continue;}if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {continue;}path.add(nums[i]);used[i] = true;backtracking(nums);path.remove(path.size() - 1);used[i] = false;}}
}

排序去重:

class Solution {private List<List<Integer>> res = new ArrayList<>();private List<Integer> path = new ArrayList<>();private boolean[] used = null;public List<List<Integer>> permuteUnique(int[] nums) {used = new boolean[nums.length];//Arrays.sort(nums);backtracking(nums);return res;}public void backtracking(int[] nums) {if (path.size() == nums.length) {res.add(new ArrayList<>(path));return;}HashSet<Integer> hashSet = new HashSet<>();//层去重for (int i = 0; i < nums.length; i++) {if (hashSet.contains(nums[i]))continue;if (used[i] == true)//枝去重continue;hashSet.add(nums[i]);//记录元素used[i] = true;path.add(nums[i]);backtracking(nums);path.remove(path.size() - 1);used[i] = false;}}
}

491. 递增子序列

Leetcode 链接
给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

题解:

  1. 回溯对象:路径
  2. 收集结果:路径长度 大于等于 2,收集结果完不可以 return
  3. 递归参数:因为全排列每层递归从头开始遍历,只需跳过已经过的数,无需 startIndex
  4. 结束条件/剪枝:不递增时 continue,注意不递增的判断 是 path 的最后一个数和当前数对比
  5. 去重操作:因为这里的数组无序切不能排序,使用 set 进行层去重,发现同层不是第一次出现 continue。
class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();public List<List<Integer>> findSubsequences(int[] nums) {backtracking(nums, 0);return res;}public void backtracking(int[] nums, int startIndex) {if (path.size() >= 2) {res.add(new ArrayList<>(path));}Set<Integer> set = new HashSet<>();for (int i = startIndex; i < nums.length; i++) {//            if (i > 0 && nums[i - 1] > nums[i]) {   错误示范
//                continue;
//            }// 递增判断if (!path.isEmpty() && path.get(path.size() - 1) > nums[i]) {continue;}// 去重if (set.contains(nums[i])) {continue;}set.add(nums[i]);path.add(nums[i]);backtracking(nums, i + 1);// 回溯path.remove(path.size() - 1);}}
}

Leetcode 刷题笔记(二十) ——回溯算法篇之分割、子集、全排列问题相关推荐

  1. Leetcode刷题笔记:栈与队列篇

    基础知识 栈和队列的原理大家应该很熟悉了,队列是先进先出,栈是先进后出. 如图所示: 那么我这里再列出四个关于栈的问题,大家可以思考一下.以下是以C++为例,使用其他编程语言的同学也对应思考一下,自己 ...

  2. LeetCode刷题笔记(算法思想 四)

    LeetCode刷题笔记(算法思想 四) 七.动态规划 斐波那契数列 70. 爬楼梯 198. 打家劫舍 213. 打家劫舍 II 信件错排 母牛生产 矩阵路径 64. 最小路径和 62. 不同路径 ...

  3. LeetCode刷题笔记2——数组2

    LeetCode刷题笔记2--数组2 重塑数组 题目 在 MATLAB 中,有一个非常有用的函数 reshape ,它可以将一个 m x n 矩阵重塑为另一个大小不同(r x c)的新矩阵,但保留其原 ...

  4. 刷题笔记(十四)--二叉树:层序遍历和DFS,BFS

    目录 系列文章目录 前言 题录 102. 二叉树的层序遍历 BFS DFS_前序遍历 107. 二叉树的层序遍历 II BFS DFS 199. 二叉树的右视图 BFS DFS 637. 二叉树的层平 ...

  5. leetcode刷题笔记——二分查找

    leetcode刷题笔记--二分查找 目前完成的贪心相关的leetcode算法题序号: 中等:80,81 困难:4 来源:力扣(LeetCode) 链接:https://leetcode-cn.com ...

  6. 卷进大厂系列之LeetCode刷题笔记:二分查找(简单)

    LeetCode刷题笔记:二分查找(简单) 学算法,刷力扣,加油卷,进大厂! 题目描述 涉及算法 题目解答 学算法,刷力扣,加油卷,进大厂! 题目描述 力扣题目链接 给定一个 n 个元素有序的(升序) ...

  7. LeetCode刷题笔记汇总

    LeetCode刷题笔记汇总 第一次刷LeetCode写的一些笔记. 1.两数之和 3.无重复字符的最长子串 15.三数之和 18.四数之和 19.删除链表的倒数第 N 个结点 20.有效的括号 21 ...

  8. LeetCode刷题笔记-动态规划-day4

    文章目录 LeetCode刷题笔记-动态规划-day4 55. 跳跃游戏 1.题目 2.解题思路 3.代码 45. 跳跃游戏 II 1.题目 2.解题思路 3.代码 LeetCode刷题笔记-动态规划 ...

  9. 小何同学的leetcode刷题笔记 基础篇(01)整数反转

    小何同学的leetcode刷题笔记 基础篇(01)整数反转[07] *** [01]数学取余法*** 对数字进行数位操作时,常见的方法便是用取余的方法提取出各位数字,再进行操作 操作(1):对10取余 ...

  10. 【leetcode刷题笔记】动态规划

    #[leetcode刷题笔记]动态规划 石子游戏 public boolean stoneGame(int[] piles) {int N = piles.length;// dp[i][j] is ...

最新文章

  1. iOS 模仿支付宝支付到账推送,播报钱数
  2. 福利 | 学习超级用户运营,都来U-Time六城巡回沙龙”!
  3. centos共享linux文件夹权限,CENTOS7 搭建文件服务器:samba共享linux文件夹
  4. 离线地图解决方案(二):地图基本控制
  5. Java中String类的常见面试题
  6. MKL学习——矩阵向量操作
  7. 哈啰出行完成新一轮2.8亿美元融资 阿里首次入股
  8. python子类_python创建子类的方法分析
  9. 洛谷 P1113 杂务
  10. (转)2017德勤技术趋势报告:未来8年,机器智能如何创造价值
  11. 连接mysql集群_mysql集群
  12. 十五个问题了解个税汇算清缴
  13. Python爬虫 Selenium实现自动登录163邮箱和Locating Elements介绍
  14. v90绝对值编码器回零_由“V90使用绝对值编码器掉电后位置丢失”所想到的
  15. 计算机英语发展,计算机发展史(英语版)
  16. 色彩搭配速成!3个实用方法帮你全面搞定配色
  17. 2021年大数据发展十大趋势:抓准一个,就能掌握先机!
  18. C语言答案写成科学记数法,c语言科学记数法_C语言中、科学计数法123456e+002具体代表什么意思、或者说怎么理解这个数_淘题吧...
  19. 使用 Windows 脚本文件 (.wsf)
  20. springboot websocket订单消息提醒

热门文章

  1. 深度学习11-tf.data详解以及猫狗图片分类实战
  2. 76----平面二次曲线的分类、消去二次交叉项、转轴变换、平面二次曲线的不变量、利用不变量确定平面二次曲线的类型和形状
  3. PyTorch:模型训练-模型参数parameters
  4. Scala:函数式编程之下划线underscore
  5. php苹果推送消息,php推送消息到IOS
  6. Linux执行fastqc报错Exception in thread “main“ java.awt.HeadlessException: No X11 DISPLAY variable was s
  7. Ubuntu下安装repo
  8. SQL Sever — 附加【如何导入外部文件数据库】
  9. RK3288_Android7.1调试uart串口屏
  10. GraphQL教程(三) .net core api