93.复原IP地址
本期本来是很有难度的,不过 大家做完 分割回文串 之后,本题就容易很多了
题目链接/文章讲解:https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%B0%E5%9D%80.html
视频讲解:https://www.bilibili.com/video/BV1XP4y1U73i/
、
第一印象:
我有个大概的思路,但是不会把String转成int,看题解在学习一下吧
看完题解的思路:
思路确实不难,难在终止条件? 如何切割? 怎么判断合法性?其实我觉得这道题好多剪枝的方法。
返回值和传参:
返回值void,传入字符串s,startIndex,另外还需要记录逗点 ‘.’ 的数量。因为这IP地址一共就是三个逗点,所以这个树深度也是确定的。
终止条件:
只要加了三次逗点,就可以return去收获结果了。
但是这里要注意,三个逗点分成了四个子串,每次都是检验逗点前面的字串是否合法。所以在收获结果的时候,还要检验最后的子串是否合法。
单层递归的逻辑:
和分割回文串那道题就是很像了,只是有一些细节上的改变。
例如,因为插入了逗点,所以下一次递归的位置就是 i + 2.
实现上的困难:
判断合法的函数我写的不对
在for循环里,如果合法,才会去递归,不合法就break,这个地方感觉怪怪的。
但是仔细想确实是,因为每个节点相当于一个for循环,只有合法的才回去递归一个,要是不合法就break,不要这个节点才对。
他这里操作字符串用的字符串直接加减,我觉得不太合理。
答案2用的stringBuilder。我需要学习一下这个东西好在哪。和字符串的一些操作
答案三有点超出能力了,二刷再说
感悟:
字符串操作太难了
在131.分割回文串中列举的分割字符串的难点,本题都覆盖了。
而且本题还需要操作字符串添加逗号作为分隔符,并验证区间的合法性。
可以说是131.分割回文串的加强版。
代码:
class Solution {
List<String> result = new ArrayList<>();
public List<String> restoreIpAddresses(String s) {
if (s.length() > 12) return result; // 算是剪枝了
backtracking(s, 0, 0);
return result;
}
private void backtracking(String s, int startIndex, int pointSum) {
//终止条件
if (pointSum == 3) {
if (isIP(s, startIndex, s.length() - 1)) {
result.add(s);
}
return;
}
//单层递归
for (int i = startIndex; i < s.length(); i++) {
//如果这段是合法的
if (isIP(s, startIndex, i)) {
s = s.substring(0, i + 1) + '.' + s.substring(i + 1);
pointSum++;
backtracking(s, i + 2, pointSum);
pointSum--;
// 回溯删掉逗点
s = s.substring(0, i + 1) + s.substring(i + 2);
} else {
break;
}
}
}
// //左闭右闭
// private boolean isIP(String s, int startIndex, int end) {
// if (end > startIndex) return false;
// //获得字串
// String number = s.substring(startIndex, end + 1);
// //如果数字开头是0,但不只是0也不合法
// if (number.charAt(0) == '0' && number.length() != 1) return false;
// //如果有非数字不合法
// for (int i = 0; i < number.length(); i++) {
// if (number.charAt(i) > '9' || number.charAt(i) < '0') {
// return false;
// }
// }
// //转换成数字
// int num = Integer.parseInt(number);
// //不在范围内不合法
// if (num > 255 || num < 0) return false;
// return true;
// }
private Boolean isIP(String 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://programmercarl.com/0078.%E5%AD%90%E9%9B%86.html
视频讲解:https://www.bilibili.com/video/BV1U84y1q7Ci、
第一印象:
这道题和组合问题,有区别吗? 我做做试试
直接秒杀!!
看完题解的思路:
之前的组合问题收集最后的结果,而子集问题是收集每个节点的结果
组合问题可能需要剪枝,有的节点不要。而子集问题就是要遍历整个树。
这道题其实也可以不用终止条件,但我还是写了。因为到for循环那,startIndex >= nums.size(),本层for循环本来也结束了。
实现时的困难:
无
感悟:
学挺好
代码:
class Solution {
LinkedList path = new LinkedList<>();
List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
//添加空集
result.add(new ArrayList<>(path));
backtracking(nums, 0);
return result;
}
private void backtracking(int[] nums, int startIndex) {
//终止条件
if (startIndex == nums.length) return;
//单层递归逻辑
for (int i = startIndex; i < nums.length; i++) {
path.add(nums[i]);
result.add(new ArrayList<>(path));
backtracking(nums, i + 1);
path.removeLast();
}
}
}
90.子集II
大家之前做了 40.组合总和II 和 78.子集 ,本题就是这两道题目的结合,建议自己独立做一做,本题涉及的知识,之前都讲过,没有新内容。
题目链接/文章讲解:https://programmercarl.com/0090.%E5%AD%90%E9%9B%86II.html
视频讲解:https://www.bilibili.com/video/BV1vm4y1F71J
第一印象:
和子集那题相比,就是有重复的元素,也就是对于一些结果要去重,不能整个树都收集了。
我试试,和组合那里去重的题目一模一样,我用index来去重,不想用额外的数组标注是否使用过。
秒杀!忘记排序了提交错一次。
看完题解的思路:
ok!
实现中的困难:
忘记排序了
感悟:
子集问题和组合问题只是收集结果的时间不一样
代码:
class Solution {
LinkedList<Integer> path = new LinkedList<>();
List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
result.add(new ArrayList<>(path));
Arrays.sort(nums);
backtracking(nums, 0);
return result;
}
private void backtracking(int[] nums, int startIndex) {
if (startIndex >= nums.length) return;
for (int i = startIndex; i < nums.length; i++) {
if (i != startIndex && nums[i] == nums[i - 1]) {
continue;
}
path.add(nums[i]);
result.add(new ArrayList<>(path));
backtracking(nums, i + 1);
path.removeLast();
}
}
}