題目
給定一個僅包含數字 2-9 的字符串,返回所有它能表示的字母組合。
給出數字到字母的映射如下(與電話按鍵相同)。注意 1 不對應任何字母。
思考與遞歸程序
解空間樹的寬度是輸入數字對應的字符的個數,深度是輸入的數字的個數。
確定回溯函數參數
與之前leetcode 216. 組合總和 III 思考分析一樣,我們需要建立兩個全局變量,一個存放葉子結點子結果,一個用來存放所有子結果。
參數:第一個是string digits(數字字符串),一個是int index.
用index記錄遍歷第幾個數字了。
vector<string> result;
string res;
void backtracking(const string& digits,int index)
確定終止條件
當index等于數字個數時收集結果,返回。
if(index == digits.size())
{result.push_back(s);return;
}
單層邏輯
取第index個數字,并且找到對應的字符集。然后for循環這個字符集(for循環處理的是當層的樹寬度有關數據)
同時注意原來的字符類型的數字,要進行轉換。
int digit = digits[index]-'0';
string letters = letterMap[digit]; //取出對應的字符集
for(int i=0;i<letters.size();i++)
{res.push_back(letters[i]);backtracking(digits,index+1);res.pop_back(); //回溯
}
異常輸入情況輸入處理
如果輸入1、*、#等字符時,我們應該返回并且打印出錯誤信息
//判斷是否有非法字符
if(digits[index]=='0' || digits[index]=='1'|| digits[index]=='*'|| isValid == false)
{isValid=false;result.clear();//res.clear(); 如果這里clear的話,返回到上一層的時候,會有個回溯操作res.pop,會導致報錯return;
}
完整代碼:
class Solution {
public:const string letterMap[10]={"", //0"", //1"abc", //2"def", //3"ghi", //4"jkl", //5"mno", //6"pqrs", //7"tuv", //8"wxyz", //9};vector<string> result;string res;bool isValid =true;void backtracking(const string& digits,int index){if(index == digits.size()){result.push_back(res);return;}//判斷是否有非法字符if(digits[index]=='0' || digits[index]=='1'|| digits[index]=='*'|| isValid == false){isValid=false;result.clear();//res.clear();return;}int digit = digits[index]-'0';string letters = letterMap[digit]; //取出對應的字符集for(int i=0;i<letters.size();i++){res.push_back(letters[i]);backtracking(digits,index+1);res.pop_back(); //回溯}}vector<string> letterCombinations(string digits) {result.clear();res.clear();isValid = true;if(digits.size() == 0) return result;backtracking(digits,0);if(isValid == false) cout<<"輸入的字符中有異常"<<endl;return result;}
};
對錯誤案例的測試:
很顯然,力扣的測試程序中并沒有考慮異常輸入
語法細節
1、函數傳參中
直接用string s相當于是拷貝了一份,而用&不用拷貝內存。
2、在函數中如果用不帶const的引用會報錯:
臨時變量不能作為非const的引用參數,換句話說就是要引用臨時變量必須帶上const,這是c++的語法規范。
函數參數作為引用,函數就有責任把函數內存操作此參數的結果給出來。但是這個是一個臨時變量,隨時可能釋放掉。所以為了避免這個現象,就加上一個規則,不帶const的臨時變量不讓通過。