日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构与算法--图论最短路径算法应用-词阶求解

發布時間:2023/12/4 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构与算法--图论最短路径算法应用-词阶求解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最短路徑案例

  • 詞梯應用,在一個詞梯中,每個單詞均由前一個單詞改變一個字母而得到。例如,我們通過一系列單字母替換而得到zero轉換為five,如下:five:zero,hero,here,hire,fire,five
  • 我們可以看成是一個無權最短路徑問題,其中每一個單詞都是一個頂點,如果兩個單詞可以通過單字母替換而互相轉換,那么他們之間就有邊
  • 假設我們有一個詞典,由于n個不同的單詞組成,大部分單詞在6~11個字母之間,我們原始數據將這些單詞存儲在一個字符串數組中。
算法分析
  • 首先我們需要一個比較方法,用來對比兩個單詞直接是否只有一個字符的不同,在這我們同時考慮增加一個字符,刪除一個字符的情況,如下代碼:
/*** 比較是否只有一個字符不同的單詞*/public static boolean oneCharOff(String word1, String word2) {if (word1 == null || word2 == null || word1.length() != word2.length()) {return false;}if (word1 == word2) {return false;}for (int i = 0; i < word1.length(); i++) {if (word1.charAt(i) != word2.charAt(i)) {if (word1.substring(i + 1, word1.length()) != word2.substring(i + 1, word2.length())) {return false;}}}return true;}/*** 比較是否只添加/刪除一個字符得到* */public static boolean oneCharAdd(String word1, String word2){if(word1 == null || word2 == null || Math.abs(word1.length() - word2.length()) != 1){return false;}String largeWord = word1.length() > word2.length() ? word2 : word1;String shortWord = word1.length() > word2.length() ? word1 : word2;Integer count = 0;Integer largePis = 0;for (int i = 0; i < shortWord.length(); i++) {if(shortWord.charAt(i) != largeWord.charAt(largePis)){count ++;if(count > 1){return false;}if(shortWord.charAt(i) != largeWord.charAt(++largePis)){return false;}}largePis++;}return true;}
  • 首先我們需要對數據進行處理,得到一個Map,其中key是單詞,value是該key單詞通過1個字母替換能夠從關鍵字變換成的一系列單詞。我們用兩個for循環來對數據進行一次遍歷,得到一個單詞的key對應的數組:
/*** 修改Map中數組對象元素*/public static void update(Map<String, List<String>> map, String key, String value) {List<String> list = map.get(key);if (list == null) {list = new ArrayList<>();map.put(key, list);}list.add(value);}/*** 方法一: 時間復雜度 O(N^2)* 處理basicWords 數組,最終 產出Map<String, List<String>>* 獲取以單詞為key, 值修改一個字符可組成的新的單詞為數組的value值的Map對象* base數組基數89000, 運行75秒*/public static Map<String, List<String>> computeAdjacentWords(List<String> basicWords) {Map<String, List<String>> adjMap = new HashMap<>();for (int i = 0; i < basicWords.size(); i++) {for (int j = i + 1; j < basicWords.size(); j++) {if (oneCharOff(basicWords.get(i), basicWords.get(j)) || oneCharAdd(basicWords.get(i), basicWords.get(j))) {update(adjMap, basicWords.get(i), basicWords.get(j));update(adjMap, basicWords.get(j), basicWords.get(i));}}}return adjMap;}
  • 以上算法可以得到我們需要的數據結構,基礎詞典轉換成我們需要的鄰接表,其中key相當于我們的所有節點,key對應的value值是鄰接節點,這樣我們就可以通過這個鄰接表來基礎上用最短路徑算法得到我們需要的詞梯信息
  • 算法的缺點在于速度太慢,詞語基數過大時候,費時比較多,時間復雜度O(N^2),我們可以對以上算法進行優化,
  • 預處理詞典信息,將轉換為Map字典,key值是關鍵字的長度,value是該長度的詞語數組,也就是我們先通過字符串長度對他進行歸類,然后繼續用之前的做法將他轉成我們需要的鄰接表Map,如下代碼:
/*** 方法二* 處理basicWords 數組,最終 產出Map<String, List<String>>* 獲取以單詞為key, 值修改一個字符可組成的新的單詞為數組的value值的Map對象* base數組基數89000, 運行16秒*/public static Map<String, List<String>> computeAdjacentWords_v1(List<String> basicWords) {Map<String, List<String>> adjMap = new HashMap<>();Map<String, List<String>> lengthMap = new HashMap<>();//先分類,按字符串長度分類for (String basicWord : basicWords) {update(lengthMap, String.valueOf(basicWord.length()), basicWord);}for (List<String> strings : lengthMap.values()) {for (int i = 0; i < strings.size(); i++) {for (int j = i + 1; j < strings.size(); j++) {if (oneCharOff(strings.get(i), strings.get(j)) || oneCharAdd(strings.get(i), strings.get(j))) {update(adjMap, strings.get(i), strings.get(j));update(adjMap, strings.get(j), strings.get(i));}}}}return adjMap;}
  • 以上算法我們先按長度分組后對每個組進行運算。

  • 我們將這個Map代表一個圖的鄰接表表示方法,在此基礎上我們只需要編寫一個案例用來運行單源最短路徑算法,然后在輸出單詞序列
    我們通過findChain方法利用上面Map鄰接表信息和兩個要被鏈接的單詞,同時返回一個Map,改Map中,關鍵字是單詞,而相應的值是從first開始的最短詞梯上的關鍵字簽名的那個單詞

  • 如上面舉例中的那個,如果開始單詞是zero,關鍵字five的值是fire, 關鍵字fire的值是hire, 關鍵字hire的值是here,等等,只要我們得到這樣一個Map鏈的結構,我們就能從后向前回溯出我們需要的詞梯信息,實現方法如下:

/*** 有權重圖最短路徑算法 實現詞梯* @param first 詞梯開始單詞* @Param second 詞梯結束單詞*/public static List<String> findChain(List<String> baseWords, String first, String second) {//處理基礎數據,得到對應 權重為1 的圖基本數據結構 用Map表示的鄰接表Map<String, List<String>> adjacentWords = computeAdjacentWords_v1(baseWords);LinkedList<String> q = new LinkedList<>();Map<String, String> previousWords = new HashMap<>();q.add(first);while (!q.isEmpty()) {String current = q.removeFirst();List<String> currentArray = adjacentWords.get(current);if (currentArray != null && currentArray.size() > 0) {for (String adjWord : currentArray) {//==null 相當于 之前know 的節點屬性為以及遍歷過,則無需在處理避免 有圈圖if(previousWords.get(adjWord) == null){//通過map,一層及一層及剝離,最終得到 second--X--Y--Z--first的map鏈previousWords.put(adjWord, current);q.add(adjWord);}}}}previousWords.put(first, null);return getChainFromPreviousMap(previousWords, first, second);}//得到詞梯隊列信息public static List<String> getChainFromPreviousMap( Map<String, String> previousWords, String first, String second){LinkedList<String> q = null;if(previousWords.get(second) != null){q = new LinkedList<>();for(String str = second; str != null ; str = previousWords.get(str)){q.addFirst(str);}}return q;}
  • 如上實現中findChain假設first是合法的單詞,通過鄰接表中的信息得到對應的鄰接單詞,將鄰接單詞都構造成指向first的一個Map,并且意見處理過的鄰接單詞不會再次處理,Map相同key存儲一次。
  • getChainFromPreviousMap使用prev Map和 second,他是Map中的一個關鍵字并返回用于形成詞梯的那些單詞,通過prev向后遍歷map,使用linkedList插表頭的形式得到正確的排序詞梯。
  • 如上得到最終的答案,關鍵步驟是我們在預處理的階段,我們利用圖論的最短路徑算法解決問題首先需要建立一個鄰接表模型,才能完成后面的Dijkstra算法求解最短路徑問題

上一篇:數據結構與算法–圖論,最短路算法,拓撲排序算法
下一篇:數據結構與算法–圖論-深度優先搜索及其應用

總結

以上是生活随笔為你收集整理的数据结构与算法--图论最短路径算法应用-词阶求解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。