程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> leetcode_wordladder2

leetcode_wordladder2

編輯:C++入門知識

leetcode_wordladder2


題目描述

Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:
Only one letter can be changed at a time
Each intermediate word must exist in the dictionary

For example,
Given:
start = “hit”
end = “cog”
dict = [“hot”,”dot”,”dog”,”lot”,”log”]

Return

[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]

解題思路

wordladder2 是wordladder的延伸,wordladder是給定起始單詞和字典,然後尋找一條最短路徑也可能沒有此路徑,wordladder2是找到所有的最短路徑。 尋找最短路徑利用廣度優先的策略,也就是BFS搜素,與其對應的是深度優先搜索DFS,這裡廣優先利用輔助隊列來實現,通常對圖、樹的數據結構進行BFS和DFS。 wordladder只需尋找最短路徑數值,我們不需要記錄路徑。當然wordladder實現的時候需要注意利用題目條件,26個小寫字母的限制,而非傳統比較字符串判斷是否可達,這樣才能滿足題目要求的復雜度。 wordladder2需要增加路徑記錄,我們在找最短路徑數值的時候每加入到隊列中一個點我們會在字典中把這個點刪去,這樣不影響最短路徑數值的記錄,但是我們需要求解所有最短路徑就不能這樣做了,我們需要將每一層(廣度優先可以理解為一層一層深入)的節點全部加入的時候才可以將這些節點從集合中一次性刪除,這裡我們對節點進行了封裝,需要記錄其前驅節點,同時要記錄該節點所處的層次,這樣我們才知道當前節點所處層次信息以及某一次層次的遍歷情況。 這裡我第一次超時了,後來進行修正,添加了一個記錄當前層次遍歷過的節點隊列,在加入隊列的時候
如果是這些節點數值則跳過不加入,按照先前的思路這些節點會被加入,但是其層次屬性會加1,實際上隊列中遍歷到這些節點的時候,這些節點的數值已經從字典中刪除了,會直接略過,如果畫圖的話會發現這是一些回路情況,這樣許多重復節點(數值一樣,層次不同)加入隊列,很影響效率然後我就用存儲當前層次所處理(從隊列中彈出並對可達節點分析)過的節點,這樣就會將一些回路節點跳過,一定程度上提高效率,然後AC通過。 計算路徑的時候注意list的插入操作,LinkedList頭結點插入,可以在最短時間內得到路徑,如果適用ArrayList估計就TLE了。

詳細代碼

public class Solution {
   public List> findLadders(String start, String end, Set dict) {
      List> resultLists = new ArrayList<>();//結果

      dict.add(start);//頭部加入
      dict.add(end);//尾部加入


      Queue queue = new LinkedList();
      queue.add(new NodeForLadder(start, 1, null));//入隊 深度1 父節點null
      Set visitedPerDeepList = new HashSet();//記錄當前層次遍歷過的節點
      int currentDeep = 1; //初始化當前深度1
      Boolean hasFound = false;
      while(!queue.isEmpty())
      {
          NodeForLadder current = queue.poll();
          if(current.deep != currentDeep)
          {
              //已經進入到下一個層次,將原先層次所有的節點先刪除掉
              dict.removeAll(visitedPerDeepList);

              //更新層次信息
              currentDeep = current.deep;

              if(hasFound)
              {
                  break;//已經找到最短路徑,再次更新層次進入下一層,說明上一層遍歷完畢,最短路徑們都已走過
              }

              visitedPerDeepList.clear();//已經遍歷的層次節點清空
          }

          visitedPerDeepList.add(current.string);//加入遍歷過的層次節點

          if(current.string.equals(end))
          {
              //找到最短路徑 添加
              resultLists.add(findLadderPath(current));
              hasFound = true; // 抵達最短層
          }
          else 
          {

            //取點 找臨街的表,這裡借助最大固定數目的變數來計算而非常規利用矩陣
            String tmp = current.string;

            //首先判斷是否還有此點,以為層次更新時會刪除上一層節點,這裡排除回路的情況
            if(!dict.contains(tmp))
            {
                continue;
            }
            for(int i=0;i findLadderPath(NodeForLadder n)
  {
      List pathList = new LinkedList<>();
      while(n != null)
      {
          pathList.add(0, n.string);
          n = n.parent;
      }
      return pathList;
  }
}

總結

代碼中的注釋就是按照上述思路來的,此題屬於AC率較低的(前五),尤其適用java來做的話對算法的要求更高,需要熟悉java集合的使用,比如頭結點插入操作LinkedList效率高於ArrayList,判斷集合中是否含有某一元素的話Set(O(1))效率高於LinkedList(O(n)),許多細節需要注意,總體的思路要正確(利用26小寫字母)以及具體編碼實現(集合選取,前驅記錄,visitedPerDeepList記錄等等)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved