93. 复原 IP 地址
链接: 参考讲解
- 遇到的困难
1 判断字符串的合法性花了很多时间,有些细节没有注意到,比如不能有前导 0
这道题的思路和切割回文串很相似,就是判断字符串合法性函数复杂了亿些。
class Solution {
List<String> res = new ArrayList<>();
public List<String> restoreIpAddresses(String s) {
if(s.length() > 12) return res; // 如果有超过12位数字则为非法字符串
backtrack(s,0,0);
return res;
}
public void backtrack(String s, int startIndex, int points){
if(points == 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);
points += 1;
backtrack(s, i+2, points);
points -= 1;
s = s.substring(0, i+1) + s.substring(i+2); //删掉标点
}else break;
}
}
// 判断子串是否合法
public boolean isValid(String s, int left, int right){
if(right < left) return false;
if(s.charAt(left) == '0' && left != right) return false; // 不能含有前导 0
int num = 0;
for(int i = left; i<=right; i++){
if(s.charAt(i) > '9' || s.charAt(i) < '0') return false; // 不能含有非数字字符
num = num*10 + (s.charAt(i) - '0');
if(num > 255) return false; // 数字不能大于255
}
return true;
}
}
78. 子集
链接: 参考讲解
与之前的组合问题不同的是这次要求收集每一个叶子节点
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> subsets = new LinkedList<>();
public List<List<Integer>> subsets(int[] nums) {
backtrack(nums,0);
return res;
}
public void backtrack(int[] nums, int startIndex){
// 把空集以及自身加上
res.add(new ArrayList<>(subsets));
if(startIndex >= nums.length) return;
for(int i = startIndex; i<nums.length; i++){
subsets.add(nums[i]);
backtrack(nums,i+1);
subsets.removeLast();
}
}
}
90. 子集 II
这题和之前做的组合总和很像,这一题也涉及到数层去重的问题。因为之前做过类似的题所以这题解起来比较顺利
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> subsets = new LinkedList<>();
int[] used;
public List<List<Integer>> subsetsWithDup(int[] nums) {
used = new int[nums.length];
Arrays.sort(nums);
backtrack(nums,0,used);
return res;
}
public void backtrack(int[] nums, int startIndex, int[] used){
// 把空集以及自身加上
res.add(new ArrayList<>(subsets));
if(startIndex >= nums.length) return;
for(int i = startIndex; i<nums.length; i++){
// used[i - 1] == 1,说明同一树枝candidates[i - 1]使用过
// used[i - 1] == 0,说明同一树层candidates[i - 1]使用过
// 而我们要对同一树层使用过的元素进行跳过
if(i > 0 && nums[i] == nums[i-1] && used[i - 1] == 0) continue; // 去重
subsets.add(nums[i]);
used[i] = 1;
backtrack(nums,i+1,used);
subsets.removeLast();
used[i] = 0;
}
}
}