231014刷题记录
参考代码随想录来刷的
关键词:回溯、切割、回溯去重
1 93.复原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 地址。
给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 ‘.’ 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
这题类似昨天刷的131. 分割回文串。切割问题转化为组合问题。
电脑画图太费时间了,后面还是手画吧。。。
class Solution {
private List<String> result;
private List<String> path;
public List<String> restoreIpAddresses(String s) {
result = new ArrayList<>();
path = new ArrayList<>();
backtracking(s, 0);
return result;
}
private void backtracking(String s, int beginIndex) {
if (path.size() == 3) {
String last = s.substring(beginIndex);
if (!isValid(last))
return;
path.add(last);
result.add(String.join(".", path));
path.remove(path.size() - 1);
return;
}
for (int i = beginIndex; i < beginIndex + 3; i++) {
// 剪枝
// 出现原因:for循环的入口条件是永真式,需要判断i是否越界以及取了前3个子串后,s中是否还剩下字符)
if (i + 1 >= s.length()) break;
String sub = s.substring(beginIndex, i + 1);
// 剪枝
// 假如当前子串不符合条件,那么往该子串中再加一个字符,肯定也不符合条件
// 例如:01、010
if (!isValid(sub)) break;
path.add(sub);
backtracking(s, i + 1);
path.remove(path.size() - 1);
}
}
private boolean isValid(String s) {
if (s.length() > 3)
return false;
if (s.length() > 1 && s.startsWith("0"))
return false;
return Integer.parseInt(s) <= 255;
}
}
2 78.子集
力扣题目链接
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
这道题与回溯模板的区别在于,没有明确的终止条件。
这道题每往path中加入一个数,即要将path加入到result中。
class Solution {
private List<List<Integer>> result;
private List<Integer> path;
public List<List<Integer>> subsets(int[] nums) {
result = new ArrayList<>();
path = new ArrayList<>();
backtracking(nums, 0);
result.add(Collections.emptyList());
return result;
}
private void backtracking(int[] nums, int beginIndex) {
for (int i = beginIndex; i < nums.length; i++) {
path.add(nums[i]);
result.add(new ArrayList<>(path));
backtracking(nums, i + 1);
path.remove(path.size() - 1);
}
}
}
3 90.子集II
力扣题目链接
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
这道题和40.组合总和II类似,涉及到去重的操作。
之前理解到(画图出来很好理解),在深度上可以使用相同的元素,但是在同一层(同一个for循环中)不能使用相同的元素。
先对原始数组排序,然后判断当前元素是否和上一个元素相同,即可判断是否重复。
class Solution {
private List<List<Integer>> result;
private List<Integer> path;
public List<List<Integer>> subsetsWithDup(int[] nums) {
result = new ArrayList<>();
path = new ArrayList<>();
Arrays.sort(nums);
backtracking(nums, 0);
return result;
}
private void backtracking(int[] nums, int beginIndex) {
result.add(new ArrayList<>(path));
for (int i = beginIndex; i < nums.length; i++) {
// 去重
if (i > beginIndex && nums[i] == nums[i - 1]) continue;
path.add(nums[i]);
backtracking(nums, i + 1);
path.remove(path.size() - 1);
}
}
}