1. 程式人生 > >LeetCode--電話號碼的字母組合

LeetCode--電話號碼的字母組合

給定一個僅包含數字 2-9 的字串,返回所有它能表示的字母組合。

給出數字到字母的對映如下(與電話按鍵相同)。注意 1 不對應任何字母。

輸入:"23"輸出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

最初拿到這個題的時候我想的是通過迴圈來解決,如果通過迴圈的話,會有很多的問題,或者可以通過迴圈來模擬回溯法也是可以實現的。先說一下我的思想,最初我想的是,在開闢好的空間裡直接放入資料,比如題目中給出的示例是23,我在放的時候,先把2中的a放三個,再把2中的b放三個,再把c放三個,但是這樣就出現了問題,那到3的時候怎麼放,如果和上邊一樣的話就會出現ad ad ad be be be cf cf cf這種情況,因為這是一個迴圈來解決的,所以存放的方式不能夠區別對待,也就是前一個怎麼放後一個還是怎麼放,所以就出現了我上邊的問題。

 這種問題無非就是兩種方式迴圈解決不掉了,那就用遞迴

class Solution {
public:
	vector<string> letterCombinations(string digits) {
		vector<string> str;
		if (digits.size() == 0)
		{
			return str;
		}
		string s;
		Combinations(digits, s, 0, str);
		return str;
	}
private:
	void Combinations(string& digits, string& s, int index, vector<string>& str)
	{
		if (index == digits.size())
		{
			str.push_back(s);
			return;
		}
		int num = digits[index] - '0';
		string letter[10] = { " ", " ", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };
		for (int i = 0; i < letter[num].size(); i++)
		{
			s.push_back(letter[num][i]);
			Combinations(digits, s, index + 1, str);
			s.pop_back();
		}
		return;
	}
};

不過自己對回溯法加遞迴的問題理解的並不是很透徹。不知道什麼時候要用這個,這裡不如就一點一點分析一下整個程式是怎麼走的。我們就拿題目示例給的23來演示一下。

 先說一下函式裡的引數,分別是題目給的23字串,以及我們排列組合之後要插入的字串s,以及index,index是用來記錄我們遞迴層數的,也就是題目給我們的digits的長度是多少就遞迴幾層,index等於digits的說明不能往下迴圈了。第四個引數就是我們的要返回的vector,注意一定要傳引用的形式。

 Combinations(digits, s, 0, str);

最初的時候傳入的引數都是空和0,之後進入函式開始遞迴。

int num = digits[index] - '0';

string letter[10] = { " ", " ", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };

for (int i = 0; i < letter[num].size(); i++)

{

s.push_back(letter[num][i]);

Combinations(digits, s, index + 1, str);

s.pop_back();

}

我們先獲取出來當前digits的對應位置的數字是多少,然後通過這個數字去我們letter數組裡邊的下標來找到他對應的字母組合。

  找到之後開始把這些字母分別插入到s字串裡邊。第一次迴圈的時候我們插入了a,然後這是再去呼叫我們的Combination函式,這時候和第一次呼叫的時候有所不同,這時候引數裡邊s已經不是空的了,而是包含一個a,index+1變成了1,str還是沒變。當進去之後,我們再次通過num獲取digits下標為1的位置的數字,然後還是找到對應的字母組合,開始遍歷,之後我們在字串s中插入了d,然後又進入了迴圈,s內容是ad,index變成了2這時候。

if (index == digits.size())

{

    str.push_back(s);

    return;

}

這個判斷條件就起了作用,把s插入到了str裡邊然後退出。這時候繼續我們讓s呼叫了pop函式,也就是把d給弄了出去,s裡邊又只剩下了a,for迴圈繼續進行,這次插入的是e,然後又遞迴,遞迴到下一層index==digits.size又把ae插入進去,然後返回,回來之後又把e給去掉了,af一樣的道理。

這時候就能看到我們的str裡邊有的是ad ae af  ,然後return一下,繼續我們的s.pop之後,s裡邊的a也沒有了,

這時候就退回到了我們的第一層遞迴,index是0的狀態,然後繼續我們的for迴圈,也就是讓letter[2][1]進去了也就是b開始進入字串s

繼續之後,bd be bf也都進來了。然後s又把b給pop了出去。c也是一樣的道理,當for迴圈結束之後,就return了。

這時候所有情況都出現了。

回溯法就是在不斷的試探,然後把試探的情況組合起來,符合的留下,不符合條件的去掉,所以如果看到題目說所有可能情況,可以往這方面考慮。不過看起來程式碼簡單,但是真正理解透徹的話, 並不是很容易。還是要多聯絡,多使用。