分割回文串
题目:131
- 一眼望去,难点大概就是:如何分割,判断是否为回文串
- 先挨个切割,然后再判断目前切割到的字符串是否为回文串,切记回溯的本质也是穷举
- 判定是否为回文串,利用双指针,头尾两指针相互靠近然后判断是不是同一字符就行,不用多说
- 如果是回文串,就加入deque这个单元答案,如果不是,继续增大结束位置
- 每遍历一次字符串s就是一组分割方案,同一层的遍历,起始位置不变,就是传入的startIndex,到下一层的时候,为了保证不重复,起始位置 + 1
- 如果起始位置 > 字符串长度,说明已经走到了一棵树的分支终点,找到了一组分割方案。
if (startIndex >= s.length()) {
lists.add(new ArrayList<>(deque));
return;
}
- 关于模拟切割线,其实就是index是上一层已经确定了的分割线,i是这一层试图寻找的新分割线
for (int i = startIndex; i < s.length(); i++) {
//如果是回文子串,则记录
if (isPalindrome(s, startIndex, i)) {
String str = s.substring(startIndex, i + 1);
deque.addLast(str);
} else {
continue;
}
//起始位置后移,保证不重复
backTracking(s, i + 1);
deque.removeLast();
}
复原IP地址
题目:93
- 更难了......还需要操作字符串添加逗号作为分隔符,回溯的话,也是直接删掉最后的分组,不单纯是一个元素了
- 先想法判断一个段位是否是有效段位
-
- 段位以0为开头的数字不合法
-
- 段位里有非正整数字符不合法
-
- 段位如果大于255了不合法
//一个段位最长为3,且表示的数字在[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++) {
//段位以0开头的数字
if (i + 1 - start > 1 && s.charAt(start) - '0' == 0) {
continue;
}
}
- 返回值以及参数:切割问题要有一个开始索引startIndex(感觉每个回溯问题都有个它......)然后因为要加入'.'作为分隔符对字符串进行一个分组,引入表示当前分组数的参数number
public void restoreIpAddressesHandler(String s, int start, int number)
- 终止条件:符合条件的分组完成,把这一个答案添加到答案集合里,然后返回。或者分组还没按规矩完成:开始索引start先到了字符串结尾,但还没有分完四组。 分完了四组,但是还没有把字符串都分完。这时候返回,继续找寻正确的分组。
if (start == s.length() && number == 4) {
result.add(stringBuilder.toString());
return;
}
if (start == s.length() || number == 4) {
return;
}
- 单层递归逻辑:不要忘记,回溯的本质就是穷举,就是从0开始一个一个试,从假设刚开始的分组只有一个数开始不断穷举,错了没事,反正可以return重来。主要是进入下一层递归和回溯的边界值
if (number < 3) {
stringBuilder.append(".");
}
number++;
restoreIpAddressesHandler(s, i + 1, number);
//这里是就算加了'.'但是开头索引是i+1,不是i+2
//因为原本的字符串s里并没有加'.',加逗号的是之前创建的stringbuilder结构
number--;
stringBuilder.delete(start + number, i + number + 2);
//去掉一个分组,在stringbuilder里,如果不在意之前的逗号数量的话,应该是(start, i + 2)
//因为还是要包含一下新加入的'.'的,而且右边界是开区间,这样正好把之前新加的'.'去掉。
//现在再考虑一下之前加的逗号,所以就成为了(start + number, i + number + 2)
//毕竟......现在的start i 是用来取原字符串s里的值的,而原字符串里没有'.'