1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        ?LeetCode刷題實(shí)戰(zhàn)127:?jiǎn)卧~接龍

        共 4750字,需瀏覽 10分鐘

         ·

        2020-12-21 15:13

        算法的重要性,我就不多說(shuō)了吧,想去大廠,就必須要經(jīng)過(guò)基礎(chǔ)知識(shí)和業(yè)務(wù)邏輯面試+算法面試。所以,為了提高大家的算法能力,這個(gè)公眾號(hào)后續(xù)每天帶大家做一道算法題,題目就從LeetCode上面選 !

        今天和大家聊的問(wèn)題叫做?單詞接龍,我們先來(lái)看題面:
        https://leetcode-cn.com/problems/word-ladder/

        Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that:


        Only one letter can be changed at a time.

        Each transformed word must exist in the word list.

        Note:


        Return 0 if there is no such transformation sequence.

        All words have the same length.

        All words contain only lowercase alphabetic characters.

        You may assume no duplicates in the word list.

        You may assume beginWord and endWord are non-empty and are not the same.

        題意


        給定兩個(gè)單詞(beginWord 和 endWord)和一個(gè)字典,找到從 beginWord 到 endWord 的最短轉(zhuǎn)換序列的長(zhǎng)度。轉(zhuǎn)換需遵循如下規(guī)則:

        • 每次轉(zhuǎn)換只能改變一個(gè)字母。

        • 轉(zhuǎn)換過(guò)程中的中間單詞必須是字典中的單詞。



        說(shuō)明:

        • 如果不存在這樣的轉(zhuǎn)換序列,返回 0。

        • 所有單詞具有相同的長(zhǎng)度。

        • 所有單詞只由小寫字母組成。

        • 字典中不存在重復(fù)的單詞。

        • 你可以假設(shè) beginWord 和 endWord 是非空的,且二者不相同。


        樣例

        示例?1:

        輸入:
        beginWord = "hit",
        endWord = "cog",
        wordList = ["hot","dot","dog","lot","log","cog"]

        輸出: 5

        解釋: 一個(gè)最短轉(zhuǎn)換序列是 "hit"?-> "hot"?-> "dot"?-> "dog"?-> "cog",
        ?????返回它的長(zhǎng)度 5。

        示例 2:

        輸入:
        beginWord = "hit"
        endWord = "cog"
        wordList = ["hot","dot","dog","lot","log"]

        輸出:?0

        解釋:?endWord "cog"?不在字典中,所以無(wú)法進(jìn)行轉(zhuǎn)換。


        解題

        本文來(lái)源:
        https://leetcode-cn.com/problems/word-ladder/solution/yan-du-you-xian-bian-li-shuang-xiang-yan-du-you-2/

        分析題意即:兩個(gè)單詞對(duì)應(yīng)位置只有一個(gè)字符不同,例如 "hit" 與 "hot",這種轉(zhuǎn)換是可以逆向的,因此,根據(jù)題目給出的單詞列表,可以構(gòu)建出一個(gè)無(wú)向(無(wú)權(quán))圖;

        如果一開始就構(gòu)建圖,每一個(gè)單詞都需要和除它以外的另外的單詞進(jìn)行比較,復(fù)雜度是 O(N wordLen),這里 N 是單詞列表的長(zhǎng)度;
        為此,我們?cè)诒闅v一開始,把所有的單詞列表放進(jìn)一個(gè)哈希表中,然后在遍歷的時(shí)候構(gòu)建圖,每一次得到在單詞列表里可以轉(zhuǎn)換的單詞,復(fù)雜度是 O(26×wordLen),借助哈希表,找到鄰居與 N無(wú)關(guān);
        使用 BFS 進(jìn)行遍歷,需要的輔助數(shù)據(jù)結(jié)構(gòu)是:
        • 隊(duì)列;

        • visited 集合。說(shuō)明:可以直接在 wordSet (由 wordList 放進(jìn)集合中得到)里做刪除。但更好的做法是新開一個(gè)哈希表,遍歷過(guò)的字符串放進(jìn)哈希表里。這種做法具有普遍意義。絕大多數(shù)在線測(cè)評(píng)系統(tǒng)和應(yīng)用場(chǎng)景都不會(huì)在意空間開銷。


        方法一:廣度優(yōu)先遍歷


        public?class?Solution?{

        ????public?int?ladderLength(String beginWord, String endWord, List wordList)?{
        ????????// 第 1 步:先將 wordList 放到哈希表里,便于判斷某個(gè)單詞是否在 wordList 里
        ????????Set wordSet = new?HashSet<>(wordList);
        ????????if?(wordSet.size() == 0?|| !wordSet.contains(endWord)) {
        ????????????return?0;
        ????????}
        ????????wordSet.remove(beginWord);
        ????????
        ????????// 第 2 步:圖的廣度優(yōu)先遍歷,必須使用隊(duì)列和表示是否訪問(wèn)過(guò)的 visited 哈希表
        ????????Queue queue?= new?LinkedList<>();
        ????????queue.offer(beginWord);
        ????????Set visited = new?HashSet<>();
        ????????visited.add(beginWord);
        ????????
        ????????// 第 3 步:開始廣度優(yōu)先遍歷,包含起點(diǎn),因此初始化的時(shí)候步數(shù)為 1
        ????????int?step = 1;
        ????????while?(!queue.isEmpty()) {
        ????????????int?currentSize = queue.size();
        ????????????for?(int?i = 0; i < currentSize; i++) {
        ????????????????// 依次遍歷當(dāng)前隊(duì)列中的單詞
        ????????????????String currentWord = queue.poll();
        ????????????????// 如果 currentWord 能夠修改 1 個(gè)字符與 endWord 相同,則返回 step + 1
        ????????????????if?(changeWordEveryOneLetter(currentWord, endWord, queue, visited, wordSet)) {
        ????????????????????return?step + 1;
        ????????????????}
        ????????????}
        ????????????step++;
        ????????}
        ????????return?0;
        ????}

        ????/**
        ?????* 嘗試對(duì) currentWord 修改每一個(gè)字符,看看是不是能與 endWord 匹配
        ?????*
        ?????* @param currentWord
        ?????* @param endWord
        ?????* @param queue
        ?????* @param visited
        ?????* @param wordSet
        ?????* @return
        ?????*/

        ????private?boolean changeWordEveryOneLetter(String currentWord, String endWord,
        ?????????????????????????????????????????????Queue queue, Set visited, Set wordSet)
        ?
        {
        ????????char[] charArray = currentWord.toCharArray();
        ????????for?(int?i = 0; i < endWord.length(); i++) {
        ????????????// 先保存,然后恢復(fù)
        ????????????char?originChar = charArray[i];
        ????????????for?(char?k = 'a'; k <= 'z'; k++) {
        ????????????????if?(k == originChar) {
        ????????????????????continue;
        ????????????????}
        ????????????????charArray[i] = k;
        ????????????????String nextWord = String.valueOf(charArray);
        ????????????????if?(wordSet.contains(nextWord)) {
        ????????????????????if?(nextWord.equals(endWord)) {
        ????????????????????????return?true;
        ????????????????????}
        ????????????????????if?(!visited.contains(nextWord)) {
        ????????????????????????queue.add(nextWord);
        ????????????????????????// 注意:添加到隊(duì)列以后,必須馬上標(biāo)記為已經(jīng)訪問(wèn)
        ????????????????????????visited.add(nextWord);
        ????????????????????}
        ????????????????}
        ????????????}
        ????????????// 恢復(fù)
        ????????????charArray[i] = originChar;
        ????????}
        ????????return?false;
        ????}
        }


        方法二:雙向廣度優(yōu)先遍歷

        已知目標(biāo)頂點(diǎn)的情況下,可以分別從起點(diǎn)和目標(biāo)頂點(diǎn)(終點(diǎn))執(zhí)行廣度優(yōu)先遍歷,直到遍歷的部分有交集。這種方式搜索的單詞數(shù)量會(huì)更小一些;
        更合理的做法是,每次從單詞數(shù)量小的集合開始擴(kuò)散;
        這里 beginVisited 和 endVisited 交替使用,等價(jià)于單向 BFS 里使用隊(duì)列,每次擴(kuò)散都要加到總的 visited 里。

        public class?Solution?{

        ????public int ladderLength(String?beginWord, String?endWord, List<String> wordList) {
        ????????// 第 1 步:先將 wordList 放到哈希表里,便于判斷某個(gè)單詞是否在 wordList 里
        ????????Set<String> wordSet = new?HashSet<>(wordList);
        ????????if?(wordSet.size() == 0?|| !wordSet.contains(endWord)) {
        ????????????return?0;
        ????????}

        ????????// 第 2 步:已經(jīng)訪問(wèn)過(guò)的 word 添加到 visited 哈希表里
        ????????Set<String> visited = new?HashSet<>();
        ????????// 分別用左邊和右邊擴(kuò)散的哈希表代替單向 BFS 里的隊(duì)列,它們?cè)陔p向 BFS 的過(guò)程中交替使用
        ????????Set<String> beginVisited = new?HashSet<>();
        ????????beginVisited.add(beginWord);
        ????????Set<String> endVisited = new?HashSet<>();
        ????????endVisited.add(endWord);

        ????????// 第 3 步:執(zhí)行雙向 BFS,左右交替擴(kuò)散的步數(shù)之和為所求
        ????????int step = 1;
        ????????while?(!beginVisited.isEmpty() && !endVisited.isEmpty()) {
        ????????????// 優(yōu)先選擇小的哈希表進(jìn)行擴(kuò)散,考慮到的情況更少
        ????????????if?(beginVisited.size() > endVisited.size()) {
        ????????????????Set<String> temp = beginVisited;
        ????????????????beginVisited = endVisited;
        ????????????????endVisited = temp;
        ????????????}

        ????????????// 邏輯到這里,保證 beginVisited 是相對(duì)較小的集合,nextLevelVisited 在擴(kuò)散完成以后,會(huì)成為新的 beginVisited
        ????????????Set<String> nextLevelVisited = new?HashSet<>();
        ????????????for?(String?word : beginVisited) {
        ????????????????if?(changeWordEveryOneLetter(word, endVisited, visited, wordSet, nextLevelVisited)) {
        ????????????????????return?step + 1;
        ????????????????}
        ????????????}

        ????????????// 原來(lái)的 beginVisited 廢棄,從 nextLevelVisited 開始新的雙向 BFS
        ????????????beginVisited = nextLevelVisited;
        ????????????step++;
        ????????}
        ????????return?0;
        ????}


        ????/**
        ?????* 嘗試對(duì) word 修改每一個(gè)字符,看看是不是能落在 endVisited 中,擴(kuò)展得到的新的 word 添加到 nextLevelVisited 里
        ?????*
        ?????* @param word
        ?????* @param endVisited
        ?????* @param visited
        ?????* @param wordSet
        ?????* @param nextLevelVisited
        ?????* @return
        ?????*/

        ????private boolean changeWordEveryOneLetter(String?word, Set<String> endVisited,
        ?????????????????????????????????????????????Set<String> visited,
        ?????????????????????????????????????????????Set<String> wordSet,
        ?????????????????????????????????????????????Set<String> nextLevelVisited) {
        ????????char[] charArray = word.toCharArray();
        ????????for?(int i = 0; i < word.length(); i++) {
        ????????????char originChar = charArray[i];
        ????????????for?(char c = 'a'; c <= 'z'; c++) {
        ????????????????if?(originChar == c) {
        ????????????????????continue;
        ????????????????}
        ????????????????charArray[i] = c;
        ????????????????String?nextWord = String.valueOf(charArray);
        ????????????????if?(wordSet.contains(nextWord)) {
        ????????????????????if?(endVisited.contains(nextWord)) {
        ????????????????????????return?true;
        ????????????????????}
        ????????????????????if?(!visited.contains(nextWord)) {
        ????????????????????????nextLevelVisited.add(nextWord);
        ????????????????????????visited.add(nextWord);
        ????????????????????}
        ????????????????}
        ????????????}
        ????????????// 恢復(fù),下次再用
        ????????????charArray[i] = originChar;
        ????????}
        ????????return?false;
        ????}
        }


        好了,今天的文章就到這里,如果覺得有所收獲,請(qǐng)順手點(diǎn)個(gè)在看或者轉(zhuǎn)發(fā)吧,你們的支持是我最大的動(dòng)力。

        上期推文:

        LeetCode1-120題匯總,希望對(duì)你有點(diǎn)幫助!
        LeetCode刷題實(shí)戰(zhàn)121:買賣股票的最佳時(shí)機(jī)
        LeetCode刷題實(shí)戰(zhàn)122:買賣股票的最佳時(shí)機(jī) II
        LeetCode刷題實(shí)戰(zhàn)123:買賣股票的最佳時(shí)機(jī) III
        LeetCode刷題實(shí)戰(zhàn)124:二叉樹中的最大路徑和
        LeetCode刷題實(shí)戰(zhàn)125:驗(yàn)證回文串
        LeetCode刷題實(shí)戰(zhàn)126:?jiǎn)卧~接龍 II


        瀏覽 72
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            91麻豆精品A片国产在线观看 | 91麻豆福利 | 99re视频这里只有精品 | 亚洲AV电影网 | 国产黄片免费观看 | 国产美女操| 视频一区 中文字幕 | 大逼操 | 操B视频免费看 | 日本无码熟妇五十路视频 |