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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

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

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

最短路徑案例

  • 詞梯應(yīng)用,在一個(gè)詞梯中,每個(gè)單詞均由前一個(gè)單詞改變一個(gè)字母而得到。例如,我們通過一系列單字母替換而得到zero轉(zhuǎn)換為five,如下:five:zero,hero,here,hire,fire,five
  • 我們可以看成是一個(gè)無權(quán)最短路徑問題,其中每一個(gè)單詞都是一個(gè)頂點(diǎn),如果兩個(gè)單詞可以通過單字母替換而互相轉(zhuǎn)換,那么他們之間就有邊
  • 假設(shè)我們有一個(gè)詞典,由于n個(gè)不同的單詞組成,大部分單詞在6~11個(gè)字母之間,我們?cè)紨?shù)據(jù)將這些單詞存儲(chǔ)在一個(gè)字符串?dāng)?shù)組中。
算法分析
  • 首先我們需要一個(gè)比較方法,用來對(duì)比兩個(gè)單詞直接是否只有一個(gè)字符的不同,在這我們同時(shí)考慮增加一個(gè)字符,刪除一個(gè)字符的情況,如下代碼:
/*** 比較是否只有一個(gè)字符不同的單詞*/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;}/*** 比較是否只添加/刪除一個(gè)字符得到* */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;}
  • 首先我們需要對(duì)數(shù)據(jù)進(jìn)行處理,得到一個(gè)Map,其中key是單詞,value是該key單詞通過1個(gè)字母替換能夠從關(guān)鍵字變換成的一系列單詞。我們用兩個(gè)for循環(huán)來對(duì)數(shù)據(jù)進(jìn)行一次遍歷,得到一個(gè)單詞的key對(duì)應(yīng)的數(shù)組:
/*** 修改Map中數(shù)組對(duì)象元素*/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);}/*** 方法一: 時(shí)間復(fù)雜度 O(N^2)* 處理basicWords 數(shù)組,最終 產(chǎn)出Map<String, List<String>>* 獲取以單詞為key, 值修改一個(gè)字符可組成的新的單詞為數(shù)組的value值的Map對(duì)象* base數(shù)組基數(shù)89000, 運(yùn)行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;}
  • 以上算法可以得到我們需要的數(shù)據(jù)結(jié)構(gòu),基礎(chǔ)詞典轉(zhuǎn)換成我們需要的鄰接表,其中key相當(dāng)于我們的所有節(jié)點(diǎn),key對(duì)應(yīng)的value值是鄰接節(jié)點(diǎn),這樣我們就可以通過這個(gè)鄰接表來基礎(chǔ)上用最短路徑算法得到我們需要的詞梯信息
  • 算法的缺點(diǎn)在于速度太慢,詞語(yǔ)基數(shù)過大時(shí)候,費(fèi)時(shí)比較多,時(shí)間復(fù)雜度O(N^2),我們可以對(duì)以上算法進(jìn)行優(yōu)化,
  • 預(yù)處理詞典信息,將轉(zhuǎn)換為Map字典,key值是關(guān)鍵字的長(zhǎng)度,value是該長(zhǎng)度的詞語(yǔ)數(shù)組,也就是我們先通過字符串長(zhǎng)度對(duì)他進(jìn)行歸類,然后繼續(xù)用之前的做法將他轉(zhuǎn)成我們需要的鄰接表Map,如下代碼:
/*** 方法二* 處理basicWords 數(shù)組,最終 產(chǎn)出Map<String, List<String>>* 獲取以單詞為key, 值修改一個(gè)字符可組成的新的單詞為數(shù)組的value值的Map對(duì)象* base數(shù)組基數(shù)89000, 運(yùn)行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<>();//先分類,按字符串長(zhǎng)度分類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;}
  • 以上算法我們先按長(zhǎng)度分組后對(duì)每個(gè)組進(jìn)行運(yùn)算。

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

  • 如上面舉例中的那個(gè),如果開始單詞是zero,關(guān)鍵字five的值是fire, 關(guān)鍵字fire的值是hire, 關(guān)鍵字hire的值是here,等等,只要我們得到這樣一個(gè)Map鏈的結(jié)構(gòu),我們就能從后向前回溯出我們需要的詞梯信息,實(shí)現(xiàn)方法如下:

/*** 有權(quán)重圖最短路徑算法 實(shí)現(xiàn)詞梯* @param first 詞梯開始單詞* @Param second 詞梯結(jié)束單詞*/public static List<String> findChain(List<String> baseWords, String first, String second) {//處理基礎(chǔ)數(shù)據(jù),得到對(duì)應(yīng) 權(quán)重為1 的圖基本數(shù)據(jù)結(jié)構(gòu) 用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 相當(dāng)于 之前know 的節(jié)點(diǎn)屬性為以及遍歷過,則無需在處理避免 有圈圖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);}//得到詞梯隊(duì)列信息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;}
  • 如上實(shí)現(xiàn)中findChain假設(shè)first是合法的單詞,通過鄰接表中的信息得到對(duì)應(yīng)的鄰接單詞,將鄰接單詞都構(gòu)造成指向first的一個(gè)Map,并且意見處理過的鄰接單詞不會(huì)再次處理,Map相同key存儲(chǔ)一次。
  • getChainFromPreviousMap使用prev Map和 second,他是Map中的一個(gè)關(guān)鍵字并返回用于形成詞梯的那些單詞,通過prev向后遍歷map,使用linkedList插表頭的形式得到正確的排序詞梯。
  • 如上得到最終的答案,關(guān)鍵步驟是我們?cè)陬A(yù)處理的階段,我們利用圖論的最短路徑算法解決問題首先需要建立一個(gè)鄰接表模型,才能完成后面的Dijkstra算法求解最短路徑問題

上一篇:數(shù)據(jù)結(jié)構(gòu)與算法–圖論,最短路算法,拓?fù)渑判蛩惴?br /> 下一篇:數(shù)據(jù)結(jié)構(gòu)與算法–圖論-深度優(yōu)先搜索及其應(yīng)用

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。