LeetCode017:電話號(hào)碼的字母組合

題目介紹

題目:電話號(hào)碼的字母組合
描述:給定一個(gè)僅包含數(shù)字 2-9 的字符串宴倍,返回所有它能表示的字母組合服球。

給出數(shù)字到字母的映射如下(與電話按鍵相同)俺亮。注意 1 不對(duì)應(yīng)任何字母估灿。

數(shù)字字母映射

示例:

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

說明: 盡管上面的答案是按字典序排列的兢交,但是你可以任意選擇答案輸出的順序摩疑。

解析

如果還記得高中學(xué)過的排列組合問題匕累,就可以發(fā)現(xiàn)以上問題是一個(gè)最簡單的組合問題渡八。假設(shè)輸入了 n 個(gè)數(shù)字,每個(gè)數(shù)字所包含的字母個(gè)數(shù)分別是 m1, m2, ..., mn霞怀,那么解的個(gè)數(shù)則為:C1m1C1m2...C1mn 惫东,也就是m1*m2*...*mn。雖然這和我們的題目關(guān)系不大毙石,但是它限定了時(shí)間復(fù)雜度的下限廉沮,我們?cè)谠O(shè)計(jì)算法時(shí)可以參考此值。

首先徐矩,我們考慮最簡單的情況滞时,假如只輸入一個(gè)數(shù)字 2,那么答案的解集是{"a", "b", "c"}滤灯,現(xiàn)在坪稽,我們輸入第二個(gè)數(shù)字 3,那就是把 "d"鳞骤、"e"窒百、"f" 分別和 "a" 組合,然后和 "b" 組合豫尽,最后再與 "c" 組合篙梢。也就是說,我們得到前面的結(jié)果美旧,復(fù)制多份渤滞,每一個(gè)結(jié)果后都增加一個(gè)當(dāng)前的字符,就可以得到最終結(jié)果榴嗅,由此可以得出第一條思路:遞歸妄呕。參考代碼如下:

public List<String> letterCombinations(String digits) {
    if(digits.length()==0)return new ArrayList<>();
    String[] letters = {"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    return letterCombinations(digits,letters,digits.length()-1);
}

private List<String> letterCombinations(String digits,String[] letters, int end) {
    List<String> result = new ArrayList<>();
    if (end==0) {
        int index = digits.charAt(end)-'2';
        for (int i = 0; i < letters[index].length(); i++) {
            result.add(String.valueOf(letters[index].charAt(i)));
        }
        return result;
    }else{
        int index = digits.charAt(end)-'2';
        for (int i = 0; i < letters[index].length(); i++) {
            // 復(fù)制前一結(jié)果
            List<String> temp = new ArrayList<>(letterCombinations(digits, letters, end-1));
            for (int j = 0; j < temp.size(); j++) {
                // 每一條結(jié)果后邊都加上當(dāng)前的一個(gè)字符
                temp.set(j, temp.get(j)+letters[index].charAt(i));
            }
            result.addAll(temp);
        }
    }
    return result;
}

但是以上的代碼并不完美,為了復(fù)制遞歸需要的數(shù)據(jù)嗽测,額外的執(zhí)行了一段for循環(huán)語句趴腋,大大增加了時(shí)間復(fù)雜度,而且由于無法使用StringBuilder等類來操作字符串的拼接论咏,額外創(chuàng)建了許多String變量优炬,又浪費(fèi)了大量的時(shí)間和空間。所以我們需要尋找一種能夠使用StringBuilder厅贪,又不需要多一層for循環(huán)的方法蠢护,這個(gè)方法就是:遞歸+回溯。

現(xiàn)在依然假設(shè)輸入了數(shù)字 2养涮,因?yàn)檫€要輸入更多的數(shù)字葵硕,所以這時(shí)還得不到最終結(jié)果,我們從數(shù)字 2 代表的結(jié)果中選擇一個(gè)字符存入到StringBuilder里贯吓,例如選擇了字符 'a'懈凹,現(xiàn)在StringBuilder里的結(jié)果就是 'a'。接下來輸入數(shù)字 3 之后悄谐,'d'介评、'e'、'f' 每個(gè)字符都要和 'a' 組合爬舰,那么我們可以把 'a' 固定在StringBuilder中们陆,加入 'd' 組成結(jié)果 "ad",然后移除 'd' 再加入 'e'情屹,組成結(jié)果 'ae'坪仇,...。假如輸入了更多數(shù)字垃你,就依法炮制椅文,再固定 "ad",然后加入 'g' 組成 "adg"惜颇,移除 'g' 再加入 'h' 組成 "adh"皆刺,...。這個(gè)過程就是回溯官还,之所以還有遞歸是因?yàn)槊看芜\(yùn)算只處理了一個(gè)輸入的數(shù)字芹橡。參考代碼如下:

public List<String> letterCombinations(String digits) {
    List<String> result = new ArrayList<>();
    if(digits.length()==0)return result;
    String[] letters = {"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    StringBuilder sb = new StringBuilder();
    letterCombinations(digits, 0, letters, sb, result);
    return result;
}

private void letterCombinations(String digits, int start,String[] letters, StringBuilder sb, List<String> result){
    if(start==digits.length()){
        if (sb.length()>0) {
            result.add(sb.toString());
        }
        return;
    }
    if (digits.charAt(start)>='2'&&digits.charAt(start)<='9'){
        for (int i = 0; i < letters[digits.charAt(start)-'2'].length(); i++) {
            // 加入一個(gè)字符
            sb.append(letters[digits.charAt(start)-'2'].charAt(i));
            // 進(jìn)入下一級(jí)運(yùn)算
            letterCombinations(digits, start+1, letters, sb, result);
            // 刪除最后加入的字符
            sb.deleteCharAt(sb.length()-1);
        }
    }else{
        letterCombinations(digits, start+1, letters, sb, result);
    }

}

可以看到遞歸+回溯算法的實(shí)現(xiàn)十分簡潔,但是也較為抽象望伦。接下來我們就以示例為例林说,看看輸入字符串為 "23" 時(shí),代碼是如何執(zhí)行的屯伞。

首先腿箩,獲取到字符 '2' 時(shí),函數(shù)進(jìn)到第一輪劣摇,代碼走到for循環(huán)中時(shí)把字符 'a' 添加到了 sb(StringBuilder實(shí)例)對(duì)象中珠移,然后就進(jìn)入了函數(shù)的第二輪,for循環(huán)將等待此遞歸函數(shù)執(zhí)行完成后再繼續(xù)運(yùn)行。這時(shí)獲取到字符 '3'钧惧,又把字符 'd' 添加到了sb中暇韧,進(jìn)入了下一輪的遞歸,也就是函數(shù)的第三輪浓瞪。

第三輪已經(jīng)得到了完整的結(jié)果懈玻,便return了,這時(shí)第二輪的函數(shù)繼續(xù)執(zhí)行乾颁,它把 sb 中的最后一個(gè)字符刪除涂乌,于是 sb 中又只剩下 'a',for循環(huán)重復(fù)這個(gè)過程之后英岭,就得到了三個(gè)結(jié)果湾盒,分別是 "ad","ae"诅妹,"af"罚勾。

現(xiàn)在,第二輪的函數(shù)結(jié)束了漾唉,sb 中依然只剩下字符 'a'荧库,回到第一輪時(shí)繼續(xù)執(zhí)行刪除語句,便把 'a' 也刪除了赵刑,然后繼續(xù)處理 'b'分衫、處理 'c',便得到了全部結(jié)果般此。

總結(jié)

其實(shí)早在研究KMP算法時(shí)蚪战,我們就見到過回溯的身影,之所以有KMP算法就是為了解決暴力算法的回溯問題铐懊,當(dāng)然不是任何情況下都能避免回溯的邀桑。

遞歸+回溯能夠解決很多實(shí)際的問題,之后的許多題目都可以用這個(gè)思路來解決科乎,但是這個(gè)算法較為抽象壁畸,需要我們多多練習(xí),才能深刻理解茅茂。

相關(guān)源碼已經(jīng)上傳到我的Github捏萍。

下題預(yù)告

題目:四數(shù)之和
描述:給定一個(gè)包含 n 個(gè)整數(shù)的數(shù)組 nums 和一個(gè)目標(biāo)值 target,判斷 nums 中是否存在四個(gè)元素 a空闲,b令杈,c 和 d ,使得 a + b + c + d 的值與 target 相等碴倾?找出所有滿足條件且不重復(fù)的四元組逗噩。
注意:答案中不可以包含重復(fù)的四元組掉丽。
示例:
給定數(shù)組 nums = [1, 0, -1, 0, -2, 2],和 target = 0异雁。
滿足要求的四元組集合為:

[
    [-1,  0, 0, 1],
    [-2, -1, 1, 2],
    [-2,  0, 0, 2]
] 

我是飛機(jī)醬捶障,如果您喜歡我的文章,可以關(guān)注我~

編程之路片迅,道阻且長残邀。唯,路漫漫其修遠(yuǎn)兮柑蛇,吾將上下而求索。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末驱闷,一起剝皮案震驚了整個(gè)濱河市耻台,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌空另,老刑警劉巖盆耽,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異扼菠,居然都是意外死亡摄杂,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門循榆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來析恢,“玉大人,你說我怎么就攤上這事秧饮∮彻遥” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵盗尸,是天一觀的道長柑船。 經(jīng)常有香客問我,道長泼各,這世上最難降的妖魔是什么鞍时? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮扣蜻,結(jié)果婚禮上逆巍,老公的妹妹穿的比我還像新娘。我一直安慰自己弱贼,他們只是感情好蒸苇,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著吮旅,像睡著了一般溪烤。 火紅的嫁衣襯著肌膚如雪味咳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天檬嘀,我揣著相機(jī)與錄音槽驶,去河邊找鬼。 笑死鸳兽,一個(gè)胖子當(dāng)著我的面吹牛掂铐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播揍异,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼全陨,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了衷掷?” 一聲冷哼從身側(cè)響起辱姨,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎戚嗅,沒想到半個(gè)月后雨涛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡懦胞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年替久,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躏尉。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蚯根,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出醇份,到底是詐尸還是另有隱情稼锅,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布僚纷,位于F島的核電站矩距,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏怖竭。R本人自食惡果不足惜锥债,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望痊臭。 院中可真熱鬧哮肚,春花似錦、人聲如沸广匙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鸦致。三九已至潮剪,卻和暖如春涣楷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背抗碰。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國打工狮斗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人弧蝇。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓碳褒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親看疗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沙峻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 前言 最先接觸編程的知識(shí)是在大學(xué)里面专酗,大學(xué)里面學(xué)了一些基礎(chǔ)的知識(shí),c語言盗扇,java語言,單片機(jī)的匯編語言等沉填;大學(xué)畢...
    oceanfive閱讀 3,044評(píng)論 0 7
  • 在C語言中,五種基本數(shù)據(jù)類型存儲(chǔ)空間長度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來閱讀 3,325評(píng)論 0 2
  • 關(guān)于數(shù)據(jù)的存儲(chǔ)結(jié)構(gòu)疗隶,以下選項(xiàng)描述正確的是( D )A: 數(shù)據(jù)所占的存儲(chǔ)空間量B: 存儲(chǔ)在外存中的數(shù)據(jù)C: 數(shù)據(jù)在計(jì)...
    IIronMan閱讀 136,084評(píng)論 7 60
  • 覺得生活之中最揣摩不定的是人心,表面現(xiàn)象與本質(zhì)存在著天然差別翼闹,表面看著很美好的其實(shí)在深處也會(huì)有污穢的一面斑鼻。如果把心...
    闌十三閱讀 393評(píng)論 0 11
  • 漫畫17部。排序按內(nèi)容特點(diǎn)或個(gè)人評(píng)價(jià)猎荠,標(biāo)題藍(lán)色高亮帶鏈的曾在個(gè)人微博或@推遍天下 即時(shí)寫過評(píng)價(jià)坚弱,可搜索。 1. 《...
    風(fēng)華布衣閱讀 547評(píng)論 0 0