文章目录
- [❇️Day 27 第七章 回溯算法 part04](#❇️Day 27 第七章 回溯算法 part04)
❇️Day 27 第七章 回溯算法 part04
✴️今日内容
- 93.复原IP地址
- 78.子集
- 90.子集II
❇️93.复原IP地址
- 本期本来是很有难度的,不过 大家做完 分割回文串 之后,本题就容易很多了
- 题目链接:https://leetcode.cn/problems/restore-ip-addresses/
- 视频讲解:https://www.bilibili.com/video/BV1XP4y1U73i/
- 文章讲解:https://programmercarl.com/0093.复原IP地址.html
自己的思路
切割问题可以抽象为树型结构,如图:
自己的代码
不需要用path存储答案了,只需要在原数组s上插入'.'
java
class Solution {
List<String> res = new ArrayList<>();
public List<String> restoreIpAddresses(String s) {
//利用StringBuilder类型好操作
StringBuilder sb = new StringBuilder(s);
dfs(sb, 0, 0);
return res;
}
//dotCount: 记录添加逗点的数量
public void dfs(StringBuilder s, int startIndex, int dotCount){
if(dotCount == 3){
if(isValid(s, startIndex, s.length() - 1)){
res.add(s.toString());
}
return;
}
for (int i = startIndex; i < s.length(); i++) {
//判断分割出来的子串是否合法
if(isValid(s, startIndex, i)){
s.insert(i + 1, '.');
dfs(s, i + 2, dotCount + 1);
s.deleteCharAt(i + 1); //回溯
}else break;
}
return;
}
//[start, end]
private boolean isValid(StringBuilder s, int start, int end) {
if (start > end) {
return false;
}
if (s.charAt(start) == '0' && start != end) { // 0开头的数字不合法
return false;
}
int num = 0;
for (int i = start; i <= end; i++) {
if (s.charAt(i) > '9' || s.charAt(i) < '0') { // 遇到⾮数字字符不合法
return false;
}
num = num * 10 + (s.charAt(i) - '0');
if (num > 255) { // 如果⼤于255了不合法
return false;
}
}
return true;
}
}
❇️78.子集
- 子集问题,就是收集树形结构中,每一个节点的结果。 整体代码其实和 回溯模板都是差不多的。
- 题目链接:https://leetcode.cn/problems/subsets/
- 视频讲解:https://www.bilibili.com/video/BV1U84y1q7Ci
- 文章讲解:https://programmercarl.com/0078.子集.html
(3.8补)有点忘了回溯法了,看了下文章思路
随想录思路
以示例中nums = [1,2,3]为例把求子集抽象为树型结构,如下:
从图中红线部分,可以看出遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合。
自己的思路
类似组合
- 确定递归函数的参数和返回值
- nums
- startIndex:确定开始下标
- 确定终止条件
- 集合为空
- 确定单层递归的逻辑
自己的代码
严格按照模板来,和组合逻辑一样,只是添加逻辑不一样
java
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> subsets(int[] nums) {
dfs(nums, 0);
return res;
}
//可以把dfs函数改成void
public List<List<Integer>> dfs(int[] nums, int startIndex){
res.add(new ArrayList<>(path));
if(startIndex >= nums.length) return res;
for (int i = startIndex; i < nums.length; i++) {
path.push(nums[i]);
dfs(nums, i + 1);
path.pop();
}
return res;
}
}
❇️90.子集II
- 题目链接:https://leetcode.cn/problems/subsets-ii/
- 大家之前做了 40.组合总和II 和 78.子集 ,本题就是这两道题目的结合,建议自己独立做一做,本题涉及的知识,之前都讲过,没有新内容。
- 视频讲解:https://www.bilibili.com/video/BV1vm4y1F71J
- 文章讲解:https://programmercarl.com/0090.子集II.html
自己的思路
和上一题一样只需要遇到相同数时判断一下前面相同的数是否被用过,所以添加参数boolean visited[]判断数有没有被用过
自己的代码
java
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
boolean[] visited;
public List<List<Integer>> subsetsWithDup(int[] nums) {
if (nums.length == 0){
res.add(path);
return res;
}
Arrays.sort(nums);
visited = new boolean[nums.length];
dfs(nums, 0);
return res;
}
public void dfs(int[] nums, int start){
res.add(new ArrayList<>(path));
if(start >= nums.length) {
return;
}
for (int i = start; i < nums.length; i++) {
if(i > 0 && nums[i] == nums[i - 1] && !visited[i - 1]){
continue;
}
visited[i] = true;
path.push(nums[i]);
dfs(nums, i + 1);
path.pop();
visited[i] = false;
}
}
}