目录
93. 复原 IP 地址
78. 子集
90. 子集 II
93. 复原 IP 地址
难度:medium
类型:回溯,切割
思路:
切割问题类似于组合问题;
需要注意的事,我们使用count来作为递归终止条件,count统计的事“.”的个数,每个IP地址有四个数,当count等于3时,如果最后一个数也符合回文条件,则是合规的IP地址。count等于3时,递归终止。
代码:
class Solution {private List<String> ans = new ArrayList<>();// 对小圆点进行计数private int count = 0;public List<String> restoreIpAddresses(String s) {if (s == null || s.length() == 0) {return ans;}backtracking(s, 0);return ans;}public void backtracking(String s, int startIndex) {if (count == 3) {if (judge(s, startIndex, s.length())) {ans.add(s);}return;}for (int i = startIndex; i < s.length(); i++) {if (judge(s, startIndex, i + 1)) {// [startIndex, i + 1)符合要求,[0, startIndex - 1)已经验证过符合IP地址// [i + 1, s.length())还没有验证,递归给下一层进行验证s = s.substring(0, i + 1) + "." + s.substring(i + 1, s.length());count++;// 添加了原点所以i+1+1backtracking(s, i + 2);s = s.substring(0, i + 1) + s.substring(i + 2, s.length());count--;} else {break;}}}// 每个整数位于 0 到 255 之间组成,且不能含有前导 0// 左闭右开public boolean judge(String str, int start, int end) {// i + 2的隐患if (start >= end) {return false;}// 前导0if (str.charAt(start) == '0' && end > start + 1) {return false;}// 每个整数位于 0 到 255 之间组成int sum = 0;for (int i = start; i < end; i++) {if (str.charAt(i) < '0' || str.charAt(i) > '9') {return false;}sum = sum * 10 + (str.charAt(i) - '0');if (sum > 255) {return false;}}return true;}}
- 时间复杂度: O(n * 2^n)
- 空间复杂度: O(n^2)
78. 子集
难度:medium
类型:回溯,子集
思路:
组合问题是收集递归树的叶子节点,子集问题就是收集递归树的每一个节点;
本题nums没有重复元素,所以不用排序和去重。
代码:
// 子集问题需要收集递归树的每一个节点
class Solution {private List<List<Integer>> list = new ArrayList<>();private List<Integer> path = new ArrayList<>();public List<List<Integer>> subsets(int[] nums) {backtracking(nums, 0);return list;}public void backtracking(int[] nums, int startIndex) {// 记录所有节点,包括空集list.add(new ArrayList<>(path));// 终止条件可以不写if (startIndex == nums.length) {return;}for (int i = startIndex; i < nums.length; i++) {path.add(nums[i]);backtracking(nums, i + 1);path.remove(path.size() - 1);}}
}
- 时间复杂度: O(n * 2^n)
- 空间复杂度: O(n)
90. 子集 II
难度:medium
类型:回溯,子集
思路:
这道题是 40.组合总和II 和 78.子集 的结合,结合了子集问题和去重方法;
子集问题:收集递归树的每一个节点
去重方法:同 40.组合总和II,可以使用used数组也可以不用。代码随想录算法训练营day27 | 39. 组合总和,40. 组合总和 II,131. 分割回文串_Chamberlain T的博客-CSDN博客
本题也可以不使用used数组来去重,因为递归的时候下一个startIndex是i+1而不是0。
如果要是全排列的话,每次要从0开始遍历,为了跳过已入栈的元素,需要使用used。
代码:
class Solution {private List<List<Integer>> ans = new ArrayList<>();private List<Integer> path = new ArrayList<>();public List<List<Integer>> subsetsWithDup(int[] nums) {Arrays.sort(nums);backtracking(nums, 0);return ans;}public void backtracking(int[] nums, int startIndex) {ans.add(new ArrayList<>(path));if (startIndex >= nums.length) {return;}for (int i = startIndex; i < nums.length; i++) {// 去重,操作同 40. 组合总和 IIif (i > startIndex && nums[i] == nums[i - 1]) {continue;}path.add(nums[i]);backtracking(nums, i + 1);path.remove(path.size() - 1);}}
}
- 时间复杂度: O(n * 2^n)
- 空间复杂度: O(n)