https://leetcode-cn.com/tag/backtracking/
递归调用的一个重要特征-要返回 回溯
https://leetcode-cn.com/problems/restore-ip-addresses/
三层for循环
class Solution {
private List res;
public List restoreIpAddresses(String s) {
res = new ArrayList<>();
for (int i = 1; i < s.length(); i++) {
String subStr = s.substring(0, i);
if (!areYouOK(subStr)) {
continue;
}
for (int j = i + 1; j < s.length(); j++) {
String subStr02 = s.substring(i, j);
if (!areYouOK(subStr02)) {
continue;
}
for (int k = j + 1; k < s.length(); k++) {
String subStr03 = s.substring(j, k);
String subStr04 = s.substring(k);
if (!areYouOK(subStr03) || !areYouOK(subStr04)) {
continue;
}
//System.out.println(subStr + "->" + subStr02 + "->" + subStr03+ "->" + subStr04);
if (howAreYou(subStr) && howAreYou(subStr02) && howAreYou(subStr03) && howAreYou(subStr04)) {
System.out.println(subStr + "->" + subStr02 + "->" + subStr03 + "->" + subStr04);
res.add(subStr + "." + subStr02 + "." + subStr03 + "." + subStr04);
}
}
}
}
return res;
}
/**
* 检查数字是否合法
* 不合法 010 00
* 合法 0 10
*/
private boolean howAreYou(String str) {
if (str.length() >= 2 && str.charAt(0) == '0') {
return false;
}
return true;
}
/**
* 检查是否在 0~255
*/
private boolean areYouOK(String str) {
if (str.length() > 3) {
return false;
}
int subIp = Integer.parseInt(str);
if (subIp <= 255) {
return true;
}
return false;
}
// /**
// * 010010
// * ["0.10.0.10","0.100.1.0"]
// */
// public static void main(String[] args) {
// //new Solution().restoreIpAddresses("25525511135");
// new Solution().restoreIpAddresses("010010");
// }
}
递归回溯
class Solution {
//字符串长度
private Integer strLen;
//字符串
private String str;
//返回List
private ArrayList res;
public List restoreIpAddresses(String s) {
strLen = s.length();
res = new ArrayList<>();
LinkedList tempLis = new LinkedList<>();
str = s;
backtrack(-1, 3, tempLis);
return res;
}
/**
* 255 255 11135
* | | |
* prev_pos curr_pos max_pos
*
* 遍历三个有效位置 curr_pos 以放置点。
* 检查从上一个点到现在点中间的部分是否有效 :
* 是 :
* 放置该点。
* 检查全部 3个点是否放好
* 是 : 将结果添加到输出列表中。
* 否 : 继续放下一个点 backtrack(curr_pos, dots - 1)。
* 回溯,移除最后一个点。
* @param prev_pos 上一个放置的点
* @param dots 待放置点的数量
*/
private void backtrack(int prev_pos, int dots, LinkedList tempLis) {
int max_pos = Math.min(strLen - 1, prev_pos + 4);
for (int curr_pos = prev_pos + 1; curr_pos < max_pos; curr_pos++) {
String subStr = str.substring(prev_pos + 1, curr_pos + 1);
if (areYouOK(subStr)) {
tempLis.addLast(subStr);
if (dots - 1 == 0) {//n-1个点即可判断结果了
//添加到结果集
addElement(curr_pos, tempLis);
} else {
backtrack(curr_pos, dots - 1, tempLis);
}
//回溯
tempLis.removeLast();
}
}
}
/**
* 如果最后一个ip段合法就把这一组结果添加到List中
*
* @param curr_pos 最后一个点的位置
*/
private void addElement(int curr_pos, LinkedList tempLis) {
String subStr = str.substring(curr_pos + 1);
//System.out.println(subStr);
if (areYouOK(subStr)) {
tempLis.addLast(subStr);
res.add(String.join(".", tempLis));
tempLis.removeLast();
}
}
/**
* 判断subNum是否在0~255之间,并且subNum不能是00、01等非法数字
* @param subNum 一段ip地址
*/
private boolean areYouOK(String subNum) {
int subStrLen = subNum.length();
if (subStrLen > 3) {
return false;
}
if (subNum.charAt(0) != '0') {
return Integer.parseInt(subNum) <= 255;
} else {//str.charAt(0) == '0'
return subStrLen == 1;
}
}
//public static void main(String[] args) {
// //ArrayList list = new ArrayList<>();
// //list.add("255");
// //list.add("255");
// //list.add("11");
// //list.add("135");
// ////255.255.11.135
// //System.out.println(String.join(".", list));
//
// //List reList = new Solution().restoreIpAddresses("010010");
// List reList = new Solution().restoreIpAddresses("25525511135");
// reList.forEach(System.out::println);
//}
}
官方答案
class Solution {
private int n;
private String s;
private LinkedList segments = new LinkedList();
private ArrayList output = new ArrayList();
/**
* Check if the current segment is valid :
* 1. less or equal to 255
* 2. the first character could be '0'
* only if the segment is equal to '0'
*/
private boolean valid(String segment) {
int m = segment.length();
if (m > 3)
return false;
return (segment.charAt(0) != '0') ? (Integer.parseInt(segment) <= 255) : (m == 1);
}
/**
* Append the current list of segments
* to the list of solutions
*/
private void update_output(int curr_pos) {
String segment = s.substring(curr_pos + 1, n);
if (valid(segment)) {
segments.add(segment);
output.add(String.join(".", segments));
segments.removeLast();
}
}
/**
* The current dot curr_pos could be placed
* in a range from prev_pos + 1 to prev_pos + 4.
* The dot couldn't be placed
* after the last character in the string.
*
* @param prev_pos the position of the previously placed dot
* @param dots number of dots to place
*/
private void backtrack(int prev_pos, int dots) {
int max_pos = Math.min(n - 1, prev_pos + 4);
for (int curr_pos = prev_pos + 1; curr_pos < max_pos; curr_pos++) {
String segment = s.substring(prev_pos + 1, curr_pos + 1);
if (valid(segment)) {
segments.add(segment); // place dot
if (dots - 1 == 0) // if all 3 dots are placed
update_output(curr_pos); // add the solution to output
else
backtrack(curr_pos, dots - 1); // continue to place dots
segments.removeLast(); // remove the last placed dot
}
}
}
public List restoreIpAddresses(String s) {
n = s.length();
this.s = s;
backtrack(-1, 3);
return output;
}
}
https://leetcode-cn.com/problems/palindrome-partitioning/
class Solution {
private List> res;
public List> partition(String s) {
res = new ArrayList<>();
List value = new ArrayList<>();
division(value, s, 0);
return res;
}
private void division(List value, String sub, int index) {
if (sub.length() == 0) {
List item = new ArrayList<>();
for (int i = 0; i < index; i++) {
item.add(value.get(i));
}
res.add(item);
return;
}
for (int i = 0; i < sub.length(); i++) {
String divi = sub.substring(0, i + 1);
String subStr = sub.substring(i + 1);
if (isHuiWen(divi)) {
value.add(index, divi);
division(value, subStr, index + 1);
}
}
}
/**
* str是否为回文串
*/
private boolean isHuiWen(String str) {
if (str.length() == 0) {
return false;
}
int left = 0;
int right = str.length() - 1;
while (right >= left) {
if (str.charAt(left) != str.charAt(right)) {
return false;
}
right--;
left++;
}
return true;
}
}
加个缓存,快速判断回文字符串
class Solution {
private List> res;
private HashSet cache;
public List> partition(String s) {
cache = new HashSet<>();
res = new ArrayList<>();
List value = new ArrayList<>();
division(value, s, 0);
return res;
}
private void division(List value, String sub, int index) {
if (sub.length() == 0) {
List item = new ArrayList<>();
for (int i = 0; i < index; i++) {
item.add(value.get(i));
}
res.add(item);
return;
}
for (int i = 0; i < sub.length(); i++) {
String divi = sub.substring(0, i + 1);
String subStr = sub.substring(i + 1);
if (cache.contains(divi)) {
value.add(index, divi);
division(value, subStr, index + 1);
} else if (isHuiWen(divi)) {
cache.add(divi);
value.add(index, divi);
division(value, subStr, index + 1);
}
}
}
/**
* str是否为回文串
*/
private boolean isHuiWen(String str) {
if (str.length() == 0) {
return false;
}
int left = 0;
int right = str.length() - 1;
while (right >= left) {
if (str.charAt(left) != str.charAt(right)) {
return false;
}
right--;
left++;
}
return true;
}
}
截取字符串太耗时了
public class Solution {
private List> res;
public List> partition(String s) {
res = new ArrayList<>();
if (s.length() == 0) {
return res;
}
LinkedList path = new LinkedList<>();
backtracking(s, 0, path);
return res;
}
/**
* @param start 起始字符的索引
* @param path 记录从根结点到叶子结点的路径
*/
private void backtracking(String s, int start, LinkedList path) {
if (start == s.length()) {
res.add(new ArrayList<>(path));
return;
}
for (int i = start; i < s.length(); i++) {
// !!!截取字符串是消耗性能的,采用传子串索引的方式判断一个子串是否是回文子串
if (!checkPalindrome(s, start, i)) {
continue;
}
path.addLast(s.substring(start, i + 1));
backtracking(s, i + 1, path);
path.removeLast();
}
}
/**
* 判断回文串
* @param left 子串的左边界,可以取到
* @param right 子串的右边界,可以取到
*/
private boolean checkPalindrome(String str, int left, int right) {
while (left < right) {
if (str.charAt(left) != str.charAt(right)) {
return false;
}
left++;
right--;
}
return true;
}
}
//public static void main(String[] args) {
// //System.out.println(new Solution().partition("aab"));
// //[["c","d","d"],["c","dd"]]
// System.out.println(new Solution().partition("cdd"));
//}