迭代:從上到下來做一件事情,for循環就是迭代的一種。
遞歸:一般我們認為遞歸就是迭代的一種。可以重復一直做一件事,直到達到某種條件時,跳出遞歸。遞歸的核心思想 1.先找遞歸出口 2.每次遞歸方法要做什么。
回溯:其實回溯和遞歸很相似,都是重復做一件事,區別就是在遞歸的方法前加“增加操作“,方法后”相應減操作“。
為了更快的了解區別,還是需要例子。LeetCode題
17. 電話號碼的字母組合
給定一個僅包含數字 2-9 的字符串,返回所有它能表示的字母組合。
給出數字到字母的映射如下(與電話按鍵相同)。注意 1 不對應任何字母。

解法思路
- 這是個排列組合問題對吧?這個排列組合可以用樹的形式表示出來;
- 當給定了輸入字符串,比如:"23",那么整棵樹就構建完成了,如下:

從上面圖來看我們可以分成兩步驟來解決問題:1. 先找數字。2.從數字對應的字母數組中找字母。3.重復步驟1,2。
這樣看來我們可以用迭代方法,也可以用遞歸和回溯來解決問題。但迭代用起來相對復雜,比較亂。
方法1:遞歸
class Solution {
private String[] letterMap= {
" ", //0
"", //1
"abc", //2
"def", //3
"ghi", //4
"jkl", //5
"mno", //6
"pqrs", //7
"tuv", //8
"wxyz" //9
};
///用迭代法思路很混亂,1.選數字 2.選數字中的字母,3 重復1.2步驟
///可以用遞歸來解決,每次先選數字,然后再選字母
List<String> lists = new ArrayList<>();
private int slen;
public List<String> letterCombinations(String digits) {
slen = digits.length();
if(slen == 0) return lists;
char[] ch = digits.toCharArray();
dfsLetter(ch, 0, "");
return lists;
}
private void dfsLetter(char[] digits, int path, String comLetter){
if(slen == path){//當前路徑已經觸底,所以把此組合放進數組中
lists.add(comLetter);
return ;
}//digits[path]表示當前的數字,通過數字知道當前數字包含的字母長度
String str = letterMap[digits[path]-'0'];
for(int i=0;i<str.length();i++)
//遞歸的關鍵,每次路徑加1便增加一個字符
dfsLetter(digits, path+1, comLetter + str.charAt(i));
}
}
注意:26行是遞歸的出口,遞歸的核心思想 1.先找遞歸出口 2.每次遞歸方法要做什么。
33行 每次遞歸的目的就是增加路徑深度path,添加一個字符str.charAt(i);
但時間復雜度很不理想,原因是String 用 + 來拼接犧牲了內存和時間,可以用回溯來優化
方法2 回溯
class Solution {
private String[] letterMap= {
" ", //0
"", //1
"abc", //2
"def", //3
"ghi", //4
"jkl", //5
"mno", //6
"pqrs", //7
"tuv", //8
"wxyz" //9
};
///用迭代法思路很混亂,1.選數字 2.選數字中的字母,3 在次選數字,4選數字中的字母,重復1.2步驟
///可以用遞歸來解決,每次先選數字,然后再選字母
List<String> lists = new ArrayList<>();
private int slen;
public List<String> letterCombinations(String digits) {
slen = digits.length();
if(slen == 0) return lists;
char[] ch = digits.toCharArray();
dfsLetter(ch, 0, new StringBuilder());
return lists;
}
private void dfsLetter(char[] digits, int path, StringBuilder sb){
if(slen == path){
lists.add(sb.toString());
return ;
}//digits[path]表示當前的數字,通過數字知道當前數字包含的字母長度
String str = letterMap[digits[path]-'0'];
for(int i=0;i<str.length();i++){
sb.append(str.charAt(i));//遞歸之前添加一個字符
dfsLetter(digits, path+1, sb);
sb.deleteCharAt(path);//遞歸后剪掉一個字符
}
}
}
回溯的核心我覺得在32行和34行
時間復雜度如下所示:

