Day24
93.复原IP地址
力扣题目链接
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。
例如:"0.1.2.201" 和 "192.168.1.1" 是 有效的 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效的 IP 地址。
思路
其实还是切割问题
递归参数
startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。
本题我们还需要一个变量pointNum,记录添加逗点的数量。
递归终止条件
本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。
pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。
然后验证一下第四段是否合法,如果合法就加入到结果集里
单层搜索的逻辑
在for (int i = startIndex; i < s.size(); i++)循环中 [startIndex, i] 这个区间就是截取的子串,需要判断这个子串是否合法。
如果合法就在字符串后面加上符号.表示已经分割。
如果不合法就结束本层循环
然后就是递归和回溯的过程:
递归调用时,下一层递归的startIndex要从i+2开始(因为需要在字符串中加入了分隔符.),同时记录分割符的数量pointNum 要 +1。
回溯的时候,就将刚刚加入的分隔符. 删掉就可以了,pointNum也要-1。
代码
class Solution {
List<String> res = new ArrayList<>();
int pointNum = 0;//记录加入的.数量
public List<String> restoreIpAddresses(String s) {
if (s.length() > 12) return res;//进行剪枝操作,如果长度大于12,直接返回
backtracking(s, 0);
return res;
}
private void backtracking(String s, int startIndex) {
if (pointNum == 3) {//递归终止条件是加入了三个.
if (isValid(s, startIndex, s.length() - 1)) {//看最后一个串是否合法
res.add(s);
}
return;
}
for (int i = startIndex; i < s.length(); i++) {
if (isValid(s, startIndex, i)) {//合法,就加入.
s = s.substring(0, i + 1) + "." + s.substring(i + 1);
pointNum++;
backtracking(s, i + 2);//加入了一个.递归是i+2
s = s.substring(0, i + 1) + s.substring(i + 2);
pointNum--;
}else break;//如果这段不合法直接break
}
}
private boolean isValid(String str, int head, int end) {//判断传入字符串的子串是否合法
if (head > end || end - head > 2) return false;//注意head可能越界
if (str.charAt(head) == '0' && end > head) return false;//多位数且首位为0不合法
int sum = 0;
for (int i = head; i <= end; i++) {
if (str.charAt(i) < '0' || str.charAt(i) > '9') return false;//特殊字符不合法
sum = sum * 10 + (str.charAt(i) - '0');
if (sum > 255) return false;//数大于255不合法
}
return true;
}
}
78.子集
力扣题目链接
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例: 输入: nums = [1,2,3] 输出: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]
思路
这个题目重点在于,子集没有固定长度,所以每一次递归都加入res中即可
先加入空,然后path中加入1,进入递归;加入1,然后path中加入2,进入递归;加入12...直到加入123,结束这层递归,弹出3,结束这层递归;弹出2,加入3,加入13...
代码
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> subsets(int[] nums) {
if (nums == null || nums.length == 0) return res;
backtracking(nums, 0);
return res;
}
private void backtracking(int[] nums, int startIndex) {
res.add(new ArrayList<>(path));
if (startIndex == nums.length) return;
for (int i = startIndex; i < nums.length; i++) {
path.addFirst(nums[i]);
backtracking(nums, i + 1);
path.removeFirst();
}
}
}
90.子集II
力扣题目链接
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
思路
和上题的区别是加上了去重的逻辑
先对数组进行排序,排序之后注意
循环的时候,如果是上层递归进来的第一次循环,就直接加元素,因为是第一个,元素数量改变了,如果不是第一个还和前一位一样,那这个子集之前考虑过了,就不用再看了
代码
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
if (nums == null || nums.length == 0) return res;
Arrays.sort(nums);
backtracking(nums, 0);
return res;
}
private void backtracking(int[] nums, int startIndex) {
res.add(new ArrayList<>(path));
if (startIndex == nums.length) return;
for (int i = startIndex; i < nums.length; i++) {
if (i > startIndex && nums[i] == nums[i - 1]) continue;//去重的逻辑在这里
path.addFirst(nums[i]);
backtracking(nums, i + 1);
path.removeFirst();
}
}
}