給定一個字符串 s,將 s 分割成一些子串,使每個子串都是迴文串。
返回 s 所有可能的分割方案。
示例:
輸入: "aab"
輸出:
[
["aa","b"],
["a","a","b"]
]
面對這種需要列出所有可能性的問題,很容易想到的就是使用回溯的方法來解決,分析問題,首先需要把一個複雜的問題分解成相對來說較爲簡單的子問題,然後將這個子問題的解進行組合就可以找到複雜問題的解了。
舉例:
aabb
先考慮在第 1 個位置切割,a | abb
這樣我們只需要知道 abb 的所有結果,然後在所有結果的頭部把 a 加入
abb 的所有結果就是 [a b b] [a bb]
每個結果頭部加入 a,就是 [a a b b] [a a bb]
aabb
再考慮在第 2 個位置切割,aa | bb
這樣我們只需要知道 bb 的所有結果,然後在所有結果的頭部把 aa 加入
bb 的所有結果就是 [b b] [bb]
每個結果頭部加入 aa,就是 [aa b b] [aa bb]
aabb
再考慮在第 3 個位置切割,aab|b
因爲 aab 不是迴文串,所有直接跳過
aabb
再考慮在第 4 個位置切割,aabb |
因爲 aabb 不是迴文串,所有直接跳過
最後所有的結果就是所有的加起來
[a a b b] [a a bb] [aa b b] [aa bb]
對這個思路進行編碼
class Solution {
String s;
List<List<String>> res = new ArrayList<>();
public List<List<String>> partition(String s) {
this.s = s;
List<String> list = new ArrayList<>();
dfs(list,0);
return res;
}
public void dfs(List<String> list,int index) {
//已經到了字符串的結尾了,把結果集放到最終解中
if (index == s.length()) {
res.add(new ArrayList<>(list));
return;
}
//不斷取更長的頭串
for (int i = index;i < s.length();i++) {
if (isPartition(index,i)) {//判斷頭串是否是迴文
String temp = s.substring(index,i+1);
list.add(temp);
//對後面的字符串進行遞歸,進行相同的處理
dfs(list,i+1);
//刪除結尾已有結果,回到上一層(回溯的精髓)
list.remove(list.size()-1);
}
}
}
//判斷字符串的某一段是否是迴文
public boolean isPartition(int start,int end) {
while (start < end) {
if (s.charAt(start) != s.charAt(end)) {
return false;
}
start++;
end--;
}
return true;
}
}
其實這樣是比較直接的解決問題了,這個解法中還有可以優化的地方,就是判斷是否是迴文的地方,我們會有很多重複的判斷。比如已經判斷過“aa”是迴文了,但是判斷“baab”是否是迴文的時候還會重複判斷,這個地方是可以優化的,我們可以用一個二維空間記錄判斷過迴文的字符串,這樣就不用重複的進行判斷了。