不久之前,我写过几篇数据结构与算法的内容,有关的是一些题目我自己做下来的心得体会。时隔多日,我现在记录下回溯算法。
按照程序员carl的指导下,学会了回溯三部曲。在组合篇,我个人觉得还是能略微得心应手的,但在字符串篇时,感觉有些力不从心了,不过在一段时间的理解下,我掌握了比较简单的方式去刷字符串的题目。一下就以两道题目为主:
核心思想就是:先分割,再判断
这边的分割就是全部的分割情况,并且只看第一层的分割情况,绝不去想第二层的情况(人脑很难想出来)
题目一:分割回文串
class Solution {
List<List<String>> lists = new ArrayList<>();
Deque<String> deque = new LinkedList<>();
public List<List<String>> partition(String s) {
backTracking(s, 0);
return lists;
}
private void backTracking(String s, int startIndex) {
// 如果起始位置大于s的大小,说明找到了一组分割方案
if (startIndex >= s.length()) {
lists.add(new ArrayList(deque));
return;
}
for (int i = startIndex; i < s.length(); i++) {
// 先切割
String str = s.substring(startIndex, i + 1);
// 如果是回文子串,则记录
if (isPalindrome(str,0,str.length()-1)) {
deque.addLast(str);
// 起始位置后移,保证不重复
backTracking(s, i + 1);
deque.removeLast();
} else {
continue;
}
}
}
// 判断是否是回文串
public boolean isPalindrome(String s, int startIndex, int end) {
while (startIndex < end) {
if (s.charAt(startIndex) != s.charAt(end)) {
return false;
}
startIndex++;
end--;
}
return true;
}
}
这边为了时间更快先,就用了双指针法,不然直接将字符串反转reverse,与原来的进行比对,也能判断是否是回文串。
题目二:复原IP地址
class Solution {
public List<String> restoreIpAddresses(String s) {
List<List<String>> res = new ArrayList<>();
List<String> finalRes = new ArrayList<>();
Deque<String> path = new ArrayDeque<>();
backtracking(res, path, 0, s);
for (int i = 0; i < res.size(); i++) {
String tempPath = "";
List<String> temp = new ArrayList<>(res.get(i));
for (String string : temp) {
if (tempPath.equals("")) {
tempPath = tempPath + string;
} else {
tempPath = tempPath + "." + string;
}
}
finalRes.add(tempPath);
}
return finalRes;
}
public void backtracking(List<List<String>> res, Deque<String> path, int startIndex, String s) {
// 终止条件
if (startIndex >= s.length()&&path.size()==4) {
res.add(new ArrayList<>(path));
return;
}
for (int i = startIndex; i < s.length(); i++) {
// 先截取字符串
String temp = s.substring(startIndex, i + 1);
if (istest(temp) && path.size() < 4) {
path.offer(temp);
backtracking(res, path, i + 1, s);
path.removeLast();
}
}
}
public boolean istest(String s) {
int length = s.length();
if (length > 3) {
return false;
}
int i = Integer.parseInt(s);
if (i > 255) {
return false;
}
if (length >= 2 && s.charAt(0)=='0') {
return false;
}
return true;
}
}
还是传统方式,如果字符串难以在回溯过程中剔除最后一位,直接将切割下来的字符放入Deque中,后续再完成拼接。
总结:其实,做此类题目时,只要想着第一层的逻辑即可,只要第一层逻辑正确,后续很难出错。