93. Restore IP Addresses
题目链接:93. Restore IP Addresses
思路链接:代码随想录回溯算法-复原IP地址
思路
这道题是挺难的,我调试了很久。
这道题与上一题分割回文串一样,要将startIndex作为分割线,还要加一个记录加入断点的参数sumPoint。在单层递归时,如果从startIndex到分割线之间的字符串符合要求的话,就在分割线所表示的字符后面加上断点,然后更新sumPoint(之后要回溯);如果不符合要求,直接break,因为如果当前的字符串不符合要求,那么下层递归的字符串是以当前的字符串为基础的,一定也是不符合要求的,同时整条已经加入断点的字符串也是不符合要求的。递归直到断点数达到3时停止,注意还要检验第三个断点之后的字符串是否符合要求,因为之前都是检验断点之前的字符串。
Code
import java.util.List;
import java.util.LinkedList;
class Solution {
// 使用回溯算法
private List<String> result = new LinkedList<>();
// 需要处理的参数:输入String s, 结果集result,起始位置:startIndex,加入断点树:sumPoint
// 返回值类型:void
private void backtracking(String s, List<String> result, int startIndex, int sumPoint) {
// 结束条件
// 当加入的断点数等于3时要结束递归
if (sumPoint == 3) {
// 因为此时还有断点之后的字符串没有检验,所以还需检验后面的字符串
if (isValid(s, startIndex, s.length() - 1)) {
result.add(s);
return;
}
return;
}
// 单层递归
for (int i = startIndex; i < s.length(); i++) {
// 检验之前的字符串是否符合要求,如果不符合,就没有必要继续递归了
if (isValid(s, startIndex, i)) {
s = s.substring(0, i + 1) + "." + s.substring(i + 1);
// System.out.println(s);
sumPoint += 1;
backtracking(s, result, i + 2, sumPoint);
// 回溯操作
sumPoint -= 1;
s = s.substring(0, i + 1) + s.substring(i + 2);
} else {
break;
}
}
}
// 左闭右闭区间
private boolean isValid(String s, int startIndex, int endIndex) {
if (startIndex > endIndex) {
return false;
}
if (s.charAt(startIndex) == '0' && startIndex != endIndex) {
// System.out.println("1");
return false;
}
Long num = Long.parseLong(s.substring(startIndex, endIndex + 1));
if (num > 255) {
// System.out.println("2");
return false;
}
// System.out.println("3");
return true;
}
public List<String> restoreIpAddresses(String s) {
backtracking(s, result, 0, 0);
return result;
}
}
78. Subsets
题目链接:78. Subsets
思路链接:代码随想录回溯算法-子集
思路
这题直接秒了,简单。
就是在组合那道题的基础上改一下就行,在每层递归path中加入元素之后,将path加入到result中就行。
Code
class Solution {
private List<List<Integer>> result = new LinkedList<>();
private List<Integer> path = new LinkedList<>();
private void backtracking(int[] nums, int startIndex) {
if (startIndex == nums.length) {
return;
}
for (int i = startIndex; i < nums.length; i++) {
path.add(nums[i]);
result.add(new LinkedList<>(path));
backtracking(nums, i + 1);
path.remove(path.size() - 1);
}
}
public List<List<Integer>> subsets(int[] nums) {
result.add(new LinkedList<>());
backtracking(nums, 0);
return result;
}
}
90. Subsets II
题目链接:90. Subsets II
思路链接:代码随想录回溯算法-子集II
思路
这题也直接秒了,简单。
就是在组合的其中一题的基础上做修改,每一次递归将增加元素之后的path加入到result中,另外需要使用used,因为这题的输入数组会出现重复的元素,虽然每个元素只能使用一次,但是仍然会出现重复的元素,因此需要used数组来记录上一个元素是否使用过。前提是要先将输入数组排序。
Code
class Solution {
private List<List<Integer>> result = new LinkedList<>();
private List<Integer> path = new LinkedList<>();
private void backtracking(int[] nums, int startIndex, int[] used) {
if (startIndex == nums.length) {
return;
}
for (int i = startIndex; i < nums.length; i++) {
if (i != 0 && nums[i] == nums[i - 1] && used[i - 1] == 0) {
continue;
}
path.add(nums[i]);
result.add(new LinkedList<>(path));
used[i] = 1;
backtracking(nums, i + 1, used);
path.remove(path.size() - 1);
used[i] = 0;
}
}
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
int[] used = new int[nums.length];
result.add(path);
backtracking(nums, 0, used);
return result;
}
}