[程式設計] 17. Letter Combinations of a Phone Number

前言

這題是 LeetCode 17 題,要使用遞迴的技巧,題目請點這兒

LeetCode 17 題的題目說明

這題是說舊手機的鍵盤上除了數字之外,還有英文字母。例如鍵盤 2 上有 "abc" 三個字母,鍵盤 3 上有 "def" 三個字母。

給一些數字,例如 23,列出可能的字串組合。在這個例中,可以列出 ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"] 這些組合。

這題如果限定給的數字有幾個,那可以用巢狀迴圈處理掉。但因為數字的個數未知,因此用「遞迴」是較好的作法。

這題所需要的遞迴技巧不高,是練習遞廻的好題目。

想法

想法可以用底下的圖來說明。下圖以使用者輸入 23 時為例。

因為一個數字就代表一個字母,所以 "23" 的長度為 2,因此輸出的結果的長度也為 2。因此,下圖中共有 2 個格子,第一個格子放 2 這個數字所代表的所有的字元的可能性,即 abc。

第二個格子就放 3 這個數字所代表的所有可能的字母,即 def。


由上圖可以看出,當第一層選 a 時,第二層有 d、e、f 這三種可能性,所以就組出 "ad","ae",以及 "af" 這三個可能。

同理,當第一層選 b 時,第二層一樣有 d、e、f 這三種可能性,那就組出 "bd","be" 以及 "bf" 這三種。

依此類推。

開始寫程式

建立對照表

第一步是建立一個對照表,讓每一個數字,可以對應到它的字串。

tbl 是一個對照表,使用陣列來實作。之後我們可以透過

tbl[2] 就取得 2 這個數字所對應的字串,即 "abc"。

遞迴函式

接著就是撰寫遞迴函式。函式的想法如前所示,底下是程式碼。

idx 代表目前的遞迴深度。

0 為第一次遞迴呼叫,
1 為第二次遞廻呼叫,
2 為第三次遞迴呼叫
依此類推。

digits 為使用者輸入的數字。若以前例而言, digits 為 "23"。

r 則代表結果字串。遞迴每次終止時, r 就代表一個可能的結果。

終止條件

第 3 行到第 7 行是終止條件

如果使用者只輸入兩個數字,如 23,那遞迴的深度為 2 (即兩次的遞廻呼叫)。所以如果 idx 為 2 時,代表這是第三次的遞迴呼叫,那代表可以終止了。

終止時,我們把結果字串 (即 r ) 推入 result 這個 vector 中,並返回。

遞迴呼叫

第 10 到 16 行為遞迴呼叫的部分。

變數 num 代表每次遞廻呼叫時,所要處理的數字。

假設使用者輸入 "23"。

那 idx == 0 時, num 便為 2。
idx == 1 時,num 便為 3。
idx == 2 時,終止遞迴呼叫!

接著就使用一個 for 迴圈,走訪字串的每個字元。

每掃到一個字元,就將字元填到 r 中對應的位置,之後進入下一個遞迴呼叫。

最終程式碼

瞭解前述的想法後,其實就不難寫出完整的程式碼了。底下是個示範,給大家參考。


留言

這個網誌中的熱門文章

由 Pandas 的 DataFrame 中取得資料

[程式設計] C++ 的字串切割

[C++]在 cin 後呼叫 getline 所遇到的問題