目录
93.复原IP地址
本期本来是很有难度的,不过 大家做完 分割回文串 之后,本题就容易很多了
题目链接/文章讲解:代码随想录
题解思路:
本题看完卡哥视频思路还是清楚的,里面的有些细节一定要注意,具体的实现方式和代码见注释,说的很详细了,搭配卡哥的视频教程就是说一整个香住了!!!
class Solution {
List<String> result = new ArrayList<>();
int pointSum = 0;
public List<String> restoreIpAddresses(String s) {
backtracking(s,0);
return result;
}
public void backtracking(String s, int startIndex){
if(pointSum == 3){
if(isValid(s, startIndex, s.length() - 1)){
result.add(s);
}
return;
}
//substring(start,end):左闭右开切割子字符串的
for(int i = startIndex; i < s.length(); i++){ //for循环横向遍历,这不需要控制的,每轮结束后直接会到下一轮
if(isValid(s, startIndex, i)){
s = s.substring(0, i + 1) + "." + s.substring(i +1); //踩过的坑1------------字符串的拼接!在切割的字符串的两端中间添加一个逗号,这里一定是s.substring(0, i + 1)从0开始切割,切割判断得到的字符串一定是整个字符串的长度加上逗号的个数,不能是从startIndex开始索引的
pointSum++;
backtracking(s, i + 2); //递归纵向遍历,需要控制的,也是回溯算法的关键,本质就是理解递归三部曲就行!!!如果是有效的整数,则在此轮中继续进行递归,每轮递归的终止条件就是当pointSUm == 3 的时候一定会终止,如果不符合就不添加到结果集里面,如果符合就添加到结果集中,然后开始回溯,回溯结束就是进行下一轮的递归操作
pointSum--;
s = s.substring(0, i + 1) + s.substring(i + 2); //踩过的坑2------------------回溯删掉逗号,继续往后判断,这里是s.substring(0, i + 1)从0开始切割,不能把之前符合的逗号删掉,只能删除刚添加的逗号,这才是真正的回溯算法
}else{
break; //切割的子字符串不是一个有效的整数,那么就没有必要再尝试更大的子字符串了,因此直接停止循环即可
}
}
}
//isValid(s, startIndex, i):有效字符串是左闭右闭的区间
public boolean isValid(String s, int start, int end){
//剪枝操作
if(start > end) return false;
//判断是否有效主要是两点
//第一点:切割的字符串开头不能是0
if(s.charAt(start) == '0' && start != end) return false;
//第二点:字符串的数组小于等于255
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) return false;
}
return true;
}
}
78.子集
子集问题,就是收集树形结构中,每一个节点的结果。 整体代码其实和 回溯模板都是差不多的。
题目链接/文章讲解:代码随想录
题解思路:
算是很常规的一道题,没看题解自己写出来的,写了这么多道题还是有肌肉记忆的!!!先把树形结构画出来代码就能写出来,然后和之前的回溯算法题目差别在于:之前都是遇到叶子节点的时候才收集结果,而本题是每递归一次就要收集结果。
class Solution {
LinkedList<Integer> path = new LinkedList<>();
List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
backtracking(nums,0);
return result;
}
public void backtracking(int[] nums, int startIndex){
result.add(new LinkedList<Integer>(path)); //这行一上来就可以直接把空集加到结果集中
if(startIndex == nums.length){
return;
}
for(int i = startIndex; i < nums.length; i++){
path.add(nums[i]);
backtracking(nums, i + 1);
path.removeLast();
}
}
}
90.子集II
大家之前做了 40.组合总和II 和 78.子集 ,本题就是这两道题目的结合,建议自己独立做一做,本题涉及的知识,之前都讲过,没有新内容。
题目链接/文章讲解:代码随想录
题解思路:
跟着卡哥代码随想录刷,只要前几道题都理解了,这题和40.组合总和II思路类似,要进行数层去重,在40.组合总和II中有详细说明,这里自己手写ac出来了还是有点小成就感的!!!本题来说不算难,理解至上,可以多看卡哥视频讲解思路也很清晰!!!
class Solution {
LinkedList<Integer> path = new LinkedList<>();
List<List<Integer>> result = new ArrayList<>();
boolean[] used;
public List<List<Integer>> subsetsWithDup(int[] nums) {
used = new boolean[nums.length];
Arrays.fill(used, false);
Arrays.sort(nums);
backtracking(nums,0);
return result;
}
public void backtracking(int[] nums, int startIndex){
result.add(new LinkedList<>(path));
if(startIndex == nums.length ) {
return;
}
for(int i = startIndex; i < nums.length; i++){
if( i >= 1 && nums[i - 1] == nums[i] && used[ i - 1] == false){ //进行数层去重
continue;
}
path.add(nums[i]);
used[i] = true;
backtracking(nums, i + 1);
path.removeLast();
used[i] = false;
}
}
}