93.复原IP地址
可以借鉴 131.分割回文串
131 题的要求是:让你把字符串 s
切分成若干个合法的回文串,返回所有的切分方法。
而本题的要求是:让你把字符串 s
切分成 4 个合法的 IP 数字,返回所有的切分方法。
所以差别,便是如何判断合法的 IP 数字
代码如下:
public boolean isValid(String s, int start, int end){
if(start > end){
return false;
}
// 子串是否以 0 开头
if(s.charAt(start) == '0' && start != end){
return false;
}
// 子串例是否有非整数字符
int num = 0;
for(int i = start; i <= end; i++){
if(s.charAt(i) > '9' || s.charAt(i) < '0'){
return false;
}
// 子串是否大于255
num = num * 10 + (s.charAt(i) - '0');
if(num > 255){
return false;
}
}
return true;
}
借用卡哥的决策树:
完整代码如下:
class Solution {
List<String> res = new LinkedList<>();
List<String> track = new LinkedList<>();
public List<String> restoreIpAddresses(String s) {
backtrack(s, 0, track);
return res;
}
public void backtrack(String s, int start, List<String> track){
if(start == s.length() && track.size() == 4){
res.add(String.join(".",track));
return;
}
for(int i = start; i < s.length(); i++){
if(!isValid(s, start, i)){
continue;
}
// 由于题中只用切成 4 个 IP数字
// 已经分解为4个部分了,就不需要继续分解
if(track.size() >= 4){
break;
}
track.add(s.substring(start, i + 1));
backtrack(s, i + 1, track);
track.remove(track.size() - 1);
}
}
public boolean isValid(String s, int start, int end){
if(start > end){
return false;
}
// 子串是否以 0 开头
if(s.charAt(start) == '0' && start != end){
return false;
}
// 子串例是否有非整数字符
int num = 0;
for(int i = start; i <= end; i++){
if(s.charAt(i) > '9' || s.charAt(i) < '0'){
return false;
}
// 子串是否大于255
num = num * 10 + (s.charAt(i) - '0');
if(num > 255){
return false;
}
}
return true;
}
}
78.子集
注:子集问题便是找树的所有节点
但因为它的集合是无序的,取过的元素不会重复取,所以for仍然从start开始
决策树由下:
可知,当剩余集合为空时,便是结束条件
完整代码如下:
class Solution {
List<List<Integer>> res = new LinkedList<>();
List<Integer> track = new LinkedList<>();
public List<List<Integer>> subsets(int[] nums) {
backtrack(nums, 0);
return res;
}
public void backtrack(int[] nums, int start){
// 由于子集问题就是该树的所有节点 -> 遍历这棵树的时候便把所有节点记录下来
res.add(new LinkedList<>(track));
if(start >= nums.length){
return;
}
for(int i = start; i < nums.length; i++){
track.add(nums[i]);
backtrack(nums, i + 1);
track.remove(track.size() - 1);
}
}
}
90.子集II
与 78.子集 问题区别便是有重复元素,便是不能有重复子集
所以便考虑如何避免重复元素
if(i > start && nums[i] == nums[i - 1]){
continue;
}
决策树如下:
所以完整代码为:
class Solution {
List<List<Integer>> res = new LinkedList<>();
List<Integer> track = new LinkedList<>();
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
backtrack(nums, 0);
return res;
}
public void backtrack(int[] nums, int start){
res.add(new LinkedList<>(track));
if(start >= nums.length){
return;
}
for(int i = start; i < nums.length; i++){
if(i > start && nums[i] == nums[i - 1]){
continue;
}
track.add(nums[i]);
backtrack(nums, i + 1);
track.remove(track.size() - 1);
}
}
}