LeetCode - 93. 复原IP地址
复原IP地址其实和切割字符串类似,只不过在切割的时候需要在原来的字符串上判断当前截取片段的可行性并添加逗点。
class Solution {
List<String> res = new ArrayList<>();
public List<String> restoreIpAddresses(String s) {
backtracking(new StringBuilder(s), 0, new StringBuilder(), 0);
return res;
}
private void backtracking(StringBuilder s, int startIdx, StringBuilder curIP, int dotNum) {
//树的深度就是3
if (dotNum == 3) {
//还需判断最后一个逗点后最后一段
if (isValidNum(s, startIdx, s.length() - 1)) {
res.add(s.toString()); //s为添加完逗点的结果,我们在原基础上进行添加
return;
}
}
for (int i=startIdx; i < s.length(); i++) {
//对字符串的固定区间进行判断
if (isValidNum(s, startIdx, i)) {
//合法的话,添加逗点,进入下一层
s.insert(i+1, '.');
dotNum++;
backtracking(s, i+2, curIP, dotNum); //因为加了一个点,下一层起始idx是i+2
dotNum--;
s.deleteCharAt(i+1);
};
}
}
private boolean isValidNum(StringBuilder s, int startIdx, int endIdx) {
if (startIdx > endIdx) return false;
if (s.charAt(startIdx) == '0' && startIdx != endIdx) return false;
long num = Long.parseLong(s.substring(startIdx, endIdx+1));
if (num > 255) return false;
return true;
}
}
LeetCode - 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;
}
private void backtracking(int[] nums, int startIdx) {
//每一次只要不直接return就都要收集结果
res.add(new ArrayList(path));
if (startIdx == nums.length) {
return;
}
for (int i = startIdx; i < nums.length; i++) {
path.add(nums[i]);
backtracking(nums, i+1);
path.removeLast();
}
}
}
LeetCode - 90. 子集 II
解题思路:这题是在上一题的思路上加上了去重逻辑,去重部分和昨天的组合问题思路类似。
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
backtracking(nums, 0, new boolean[nums.length]);
return res;
}
private void backtracking(int[] nums, int startIdx, boolean[] used) {
res.add(new ArrayList(path));
if (startIdx == nums.length) return;
for (int i=startIdx; i < nums.length; i++) {
if (i > 0 && nums[i] == nums[i-1] && !used[i-1]) continue; // duplicated in same level
path.add(nums[i]);
used[i] = true;
backtracking(nums, i+1, used);
used[i] = false;
path.removeLast();
}
}
}