文章目录
- 前言
- 一、分割回文串(力扣131)
- 二、复原IP地址(力扣93)
- 三、子集(力扣78)
- 总结
前言
1、分割回文串
2、复原IP地址
3、子集
一、分割回文串(力扣131)
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
回文串 是正着读和反着读都一样的字符串。
思路:
关键在于[startIndex,i] 这个区间就是我们切割的子串【重点!!!】
startIndex就相当于是切割线!!!
整体步骤:
1、如何模拟切割线
2、递归如何终止
3、如何获取子串
4、判断回文
class Solution {
List<List<String>> res = new ArrayList<>();
LinkedList<String> paths = new LinkedList<>();
public List<List<String>> partition(String s) {
backtracking(s,0);
return res;
}
public void backtracking(String s,int startIndex){
if(startIndex==s.length()){
res.add(new ArrayList<>(paths));
return ;
}
for(int i=startIndex;i<s.length();i++){
if(isPalinderome(s,startIndex,i)){
String str = s.substring(startIndex,i+1);
paths.add(str);
}else{
continue;
}
backtracking(s,i+1);
paths.removeLast();//回溯
}
}
public boolean isPalinderome(String s,int start,int end){
for(int i=start,j=end;i<j;i++,j--){
if(s.charAt(i)!=s.charAt(j)){
return false;
}
}
return true;
}
}
二、复原IP地址(力扣93)
有效 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 中的任何数字。你可以按 任何 顺序返回答案。
思路:
与切割回文串类似:
关键在于切割 切割出来的子串区间 [stratIndex,i] 以及一些字符串的拼接操作,增加"." 判断子串是否合法等等
结束判断:
1、“.”逗点数量已经==3时,需要判断最后一段截取的子串是否合法,如果合法,收集结果
字符串拼接:
1、如果当前截取的子串合法
2、拼接子串(加“.”)
3、递归 (细节:参数不再是i+1 而是i+2)
4、回溯(子串也要退回之前的状态 把“.”去掉)
判断子串是否合法:
1、两位数及以上时 第一位如果为0 不合法
2、包含除0-9以外的其他字符 不合法
3、数值大于255 不合法
class Solution {
List<String> res = new ArrayList<>();
public List<String> restoreIpAddresses(String s) {
if(s.length()>12) return res;
backtracking(s,0,0);
return res;
}
public void backtracking(String s,int startIndex,int pointSum){
if(pointSum==3){
//判断最后一个部分是不是合法
if(isValid(s,startIndex,s.length()-1)){//左闭右闭区间
//加入结果集
res.add(s);
}
return ;
}
for(int i=startIndex;i<s.length();i++){
//判断所截取子串是否合法
if(isValid(s,startIndex,i)){
s=s.substring(0,i+1)+"."+s.substring(i+1);
//插入逗号
pointSum++;
backtracking(s,i+2,pointSum);
pointSum--;
//删除逗号
s=s.substring(0,i+1)+s.substring(i+2);
}else{
continue;
}
}
}
public boolean isValid(String s,int start,int end){
if(start>end){
return false;
}
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;
}
num = num*10+(s.charAt(i)-'0');
if(num>255)return false;
}
return true;
}
}
三、子集(力扣78)
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
以示例中nums = [1,2,3]为例把求子集抽象为树型结构,如下:
求取子集问题,不需要任何剪枝!因为子集就是要遍历整棵树。
遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合。
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> paths = new LinkedList<>();
public List<List<Integer>> subsets(int[] nums) {
backtracking(nums,0);
return res;
}
public void backtracking(int[] nums,int startIndex){
res.add(new ArrayList<>(paths)); //遍历这棵树的时候,把所有结点记录下来
if(startIndex==nums.length){
return ;
}
for(int i=startIndex;i<nums.length;i++){
paths.add(nums[i]);
backtracking(nums,i+1);
paths.removeLast();
}
}
}
总结
如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!