LeetCode 93 复原IP地址
思路
考虑回溯三要素:
- 回溯函数的参数和返回值 参数:字符串s,下一子串的开始索引start 返回值:空 全局变量:结果集result,分割路径path
- 回溯函数的结束条件
当path长度为4时
- 如果start也等于s的长度,就把path中的子串用“.”连接,加入result
- 否则违背ip规则,直接返回
- 回溯搜索的遍历过程
对从start+1开始的三个分割位置循环(因为0~255最多是三位数)
- 分割出的子串是否满足,在0~255之间,没有前导0。不满足则跳过本次循环
- 把分割出的子串加入path
- 递归调用回溯函数
- 还原path
解法
class Solution {
List<String> result;
List<String> path;
public List<String> restoreIpAddresses(String s) {
result = new ArrayList<>();
path = new ArrayList<>();
backTracking(s, 0);
return result;
}
public void backTracking(String s, int start) {
if (path.size() == 4) {
if (start == s.length()) {
StringBuilder ip = new StringBuilder();
for (int i = 0; i < path.size(); i++) {
ip.append(path.get(i) + ".");
}
ip.deleteCharAt(ip.length()-1);
result.add(ip.toString());
return ;
}
else {
return ;
}
}
for (int i = start+1; i <= Math.min(start+3, s.length()); i++) {
String ip = s.substring(start, i);
if (ip.length() > 1 && ip.charAt(0) == '0') {
continue;
}
if (Integer.valueOf(ip) > 255) {
continue;
}
path.add(ip);
backTracking(s, i);
path.remove(path.size()-1);
}
}
}
LeetCode 78 子集
思路
由于子集的选取没有任何限制,在搜索这个树时所有节点都要向result中添加子集 考虑回溯三要素:
- 回溯函数的参数和返回值 参数:集合nums,开始索引start 返回值:空 全局变量:结果集result,选择路径path
- 回溯函数的结束条件 start等于nums长度,没有可选元素,返回
- 回溯搜索的遍历过程
从start开始的每个元素循环
- 加入path
- 向result中添加path副本
- 递归调用回溯函数
- 还原path
解法
class Solution {
List<List<Integer>> result;
List<Integer> path;
public List<List<Integer>> subsets(int[] nums) {
result = new ArrayList<>();
path = new ArrayList<>();
result.add(new ArrayList<>(path));
backTracking(nums, 0);
return result;
}
public void backTracking(int[] nums, int start) {
if (start == nums.length) {
return ;
}
for (int i = start; i < nums.length; i++) {
path.add(nums[i]);
result.add(new ArrayList<>(path));
backTracking(nums, i+1);
path.remove(path.size()-1);
}
}
}
LeetCode 90 子集II
思路
nums中可能有重复元素,但子集和子集和之间不可重复,涉及到剪枝去重 考虑去重:
- 为了让相同的元素相邻,首先要对数组排序
- 和组合去重类似,如果一个元素与他前面的元素相同,仅当前面的元素也在子集中,才可以把此元素加入子集。故需要一个标志数组
考虑回溯三要素:
- 回溯函数的参数和返回值 参数:nums,开始索引start 返回值:空 全局变量:结果集result,选择路径path,标志数组inPath
- 回溯函数的结束条件 start等于nums长度,没有元素可选择,返回
- 回溯搜索的遍历过程
从start开始对每个元素i循环
- 如果i与前一个重复,且inPath[i-1]为假,跳过本次循环
- 把nums[i]加入path,inPath[i]置为真
- path加入result
- 递归调用回溯函数
- 还原path,inPath[i]置为假
解法
class Solution {
List<List<Integer>> result;
List<Integer> path;
boolean[] inPath;
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
result = new ArrayList<>();
path = new ArrayList<>();
inPath = new boolean[nums.length];
result.add(new ArrayList<>(path));
backTracking(nums, 0);
return result;
}
public void backTracking(int[] nums, int start) {
if (start == nums.length) {
return ;
}
for (int i = start; i < nums.length; i++) {
if (i > 0 && nums[i] == nums[i-1] && !inPath[i-1]) {
continue;
}
path.add(nums[i]);
inPath[i] = true;
result.add(new ArrayList<>(path));
backTracking(nums, i+1);
inPath[i] = false;
path.remove(path.size()-1);
}
}
}
今日收获总结
今日学习2h,去重之前都要对数组排序