93.复原IP地址
思路:切割问题,原理上还是抽象成树形结构,然后使用回溯法。
class Solution {
private List<String> res = new ArrayList<>();
public List<String> restoreIpAddresses(String s) {
backtracking(s, 0, 0);
return res;
}
public void backtracking(String s, int start, int pointNum) {
if (pointNum == 3) {
if (isValid(s, start, s.length() - 1)) {
res.add(s);
} else {
return;
}
}
for (int i = start; i < s.length(); i++) {
if (isValid(s, start, i)) {
s = s.substring(0, i + 1) + "." + s.substring(i + 1);
backtracking(s, i + 2, pointNum + 1);
s = s.substring(0, i + 1) + s.substring(i + 2);
} else {
return;
}
}
}
public boolean isValid(String s, int start, int end) {
if (start > end) return false; // 如果出现把.加到最后的情况,这里不加判断就会越界
if (s.charAt(start) == '0' && start != end) return false;
int num = 0;
for (int i = start; i <= end; i++) {
if (s.charAt(i) < '0' || s.charAt(i) > '9') return false;
num *= 10;
num += s.charAt(i) - '0';
if (num > 255) return false;
}
return true;
}
}
本题的代码在时间上仍有很大的优化空间。后续补充。
78.子集
思路:回溯法,首先要将问题抽象成树形结构。注意,分割问题和组合问题收集结果是在树的叶子节点,子集问题收集结果是收集数中的所有节点。
class Solution {
private List<List<Integer>> res = new ArrayList<>();
private List<Integer> path = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
backtracking(nums, 0);
return res;
}
public void backtracking(int[] nums, int start) {
res.add(new ArrayList<>(path));
for (int i = start; i < nums.length; i++) {
path.add(nums[i]);
backtracking(nums, i + 1);
path.remove(path.size() - 1);
}
}
}
90.子集II
思路:与上一题思路相同,但是要考虑去重的问题。注意,这里是要在同一个树层上进行去重,而不是在同一个树杈上进行去重。
class Solution {
private List<List<Integer>> res = new ArrayList<>();
private List<Integer> path = new ArrayList<>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
backtracking(nums, 0);
return res;
}
public void backtracking(int[] nums, int start) {
res.add(new ArrayList<>(path));
for (int i = start; i < nums.length; i++) {
if (i > start && nums[i] == nums[i - 1]) continue;
path.add(nums[i]);
backtracking(nums, i + 1);
path.remove(path.size() - 1);
}
}
}