目录
131.分割回文串
题目:给你一个字符串 s,请你将s分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。回文串 是正着读和反着读都一样的字符串。
思路:分割问题和组合问题有相似之处,一个是选数,一个是选分割线。
class Solution {
List<List<String>> res=new ArrayList<>();
List<String> path=new ArrayList<>();
String s;
public List<List<String>> partition(String s) {
this.s=s;
traceback(0);
return res;
}
public void traceback(int start){
//因为只有是回文字符串的时候才会回溯i+1,
//所以start超过长度,说明一定找到了一组结果
if(start>=s.length()){
res.add(new ArrayList(path));
return;
}
//!!标准的回溯找所有分割方法
for(int i=start;i<s.length();i++){
String substring=s.substring(start,i+1);
if(isParlindrome(substring)){
path.add(substring);
traceback(i+1);
path.remove(path.size()-1);
}
}
}
//判断字串是否是回文字符串
public boolean isParlindrome(String s){
int left=0,right=s.length()-1;
while(left<right){
if(s.charAt(left)!=s.charAt(right))return false;
left++;
right--;
}
return true;
}
}
93.复原ip地址
题目:
思路:和上一个题一样,也是分割。有一些小点不同,还有一些写的时候的错误记录,都标到代码里面了。
class Solution {
List<String> res=new ArrayList<>();
StringBuilder sb=new StringBuilder();
String s;
public List<String> restoreIpAddresses(String s) {
if(s.length()<4 || s.length()>12)return res;
this.s=s;
traceback(0,0);
return res;
}
//分割次数相比上题有限制,所以多了一个参数n记录分割次数
public void traceback(int start,int n){
//!!!这里多一个n==4,是为了防止n<4的时候也返回结果。
if(start>=s.length()&&n==4){
res.add(sb.deleteCharAt(sb.length()-1).toString());
sb.append('.');//!!!!
//错误记录1
//这个是为了防止回溯sb的时候,删除的个数确定,多删的补回来凑数
//!!!!!
return;
}
for(int i=start;i<s.length();i++){
String substring=s.substring(start,i+1);
//n<4,是分割次数过多就跳过
if(isIP(substring)&&n<4){
sb.append(substring);
sb.append('.');
traceback(i+1,n+1);
for(int j=0;j<=substring.length();j++){
sb.deleteCharAt(sb.length()-1);
}
}
}
}
public boolean isIP(String s){
if(s.length()>3 || s.length()==0)return false;
if(s.length()>1 && s.charAt(0)=='0')return false;
//错误记录2
//!!!!!这个一定是'0',不能是0
if(Integer.parseInt(s)>255)return false;
return true;
}
}
卡哥的java代码 主要看最后,回溯时sb删除的那行
class Solution {
List<String> result = new ArrayList<String>();
StringBuilder stringBuilder = new StringBuilder();
public List<String> restoreIpAddresses(String s) {
restoreIpAddressesHandler(s, 0, 0);
return result;
}
// number表示stringbuilder中ip段的数量
public void restoreIpAddressesHandler(String s, int start, int number) {
// 如果start等于s的长度并且ip段的数量是4,则加入结果集,并返回
if (start == s.length() && number == 4) {
result.add(stringBuilder.toString());
return;
}
// 如果start等于s的长度但是ip段的数量不为4,或者ip段的数量为4但是start小于s的长度,则直接返回
if (start == s.length() || number == 4) {
return;
}
// 剪枝:ip段的长度最大是3,并且ip段处于[0,255]
for (int i = start; i < s.length() && i - start < 3 && Integer.parseInt(s.substring(start, i + 1)) >= 0
&& Integer.parseInt(s.substring(start, i + 1)) <= 255; i++) {
// 如果ip段的长度大于1,并且第一位为0的话,continue
if (i + 1 - start > 1 && s.charAt(start) - '0' == 0) {
continue;
}
stringBuilder.append(s.substring(start, i + 1));
// 当stringBuilder里的网段数量小于3时,才会加点;如果等于3,说明已经有3段了,最后一段不需要再加点
if (number < 3) {
stringBuilder.append(".");
}
number++;
restoreIpAddressesHandler(s, i + 1, number);
number--;
// 删除当前stringBuilder最后一个网段,注意考虑点的数量的问题
stringBuilder.delete(start + number, i + number + 2);
}
}
}
关于回溯时sb删除之前增加的网段。
我是倒数一个一个删,并且最后一个后面也加了点,保证数量不出错。
卡哥后面的java代码使用delete函数,确定前后索引。但是仍然存在最后一个网段少点,删除数量不同的问题,他这个索引i+number+2在最后一个字段会超过字符长度。
但是他的代码没有报错是为什么?
点到stringbuilder的delete函数源码看来一下:
可以看到:delete函数的第二个参数如果超过了sb的长度并不会报错,而是会让end=count