LeetCode演算法題-Longest Word in Dictionary(Java實現)
這是悅樂書的第303 次更新,第322 篇原創
01 看題和準備
今天介紹的是LeetCode演算法題中Easy級別的第171題(順位題號是720)。給出表示英語詞典的字串單詞陣列,找到單詞中長度最長的單詞,此單詞可以通過陣列中的其他單詞一次次構建一個字元而得來。如果有多個可能的答案,則返回字典順序最小的最長單詞。如果沒有答案,則返回空字串。例如:
輸入:words = [“w”,“wo”,“wor”,“worl”,“world”]
輸出:“world”
說明:“world”這個詞可以通過“w”,“wo”,“wor”和“worl”一次構建一個字元。
輸入:words = [“a”,“banana”,“app”,“appl”,“ap”,“apply”,“apple”]
輸出:“apple”
說明:“apply”和“apple”都可以從字典中的其他單詞構建。但是,“apple”在詞典上比“apply”更小(靠前)。
注意:
-
輸入中的所有字串僅包含小寫字母。
-
單詞的長度將在[1,1000]範圍內。
-
單詞[i]的長度將在[1,30]的範圍內。
本次解題使用的開發工具是eclipse,jdk使用的版本是1.8,環境是win7 64位系統,使用Java語言編寫和測試。
02 第一種解法
在解題前,需要先注意題目中的幾個資訊,一是滿足題目條件的結果字串,是有一個個字元累加起來的,在我的一次提交中,有{"ew","ewq","ewqz"}這三個字串,我的演算法算出來是第三個"ewqz",但其實它還缺少一個"e",是不符合題目要求的。二是如果滿足題目條件的字串有兩個或者多個,需要去比較誰更小,也就是按照字母順序由小到大排列的,誰更靠前誰更小。
思路是先將字串放進HashMap中,key為每一個單詞,value為單詞的長度。迴圈單詞陣列,比較誰的長度更小,此處分為兩種情況處理:一是大於已有最大長度,二是等於已有最大長度,另外,無論遇到那種情況,都需要去判斷當前字元是否是由單個單詞一次次累加變成的,對此單獨寫了一個方法判斷當前單詞是否符合題目要求的方法isExists。針對第二種情況,需要去比較兩個單詞的大小,也寫了一個額外的方法isMin來判斷,如果滿足,就將結果字串更新,最長長度保持不變。
Map<String, Integer> map = new HashMap<String, Integer>(); public String longestWord(String[] words) { for (String str : words) { map.put(str, str.length()); } int len = Integer.MIN_VALUE; String result = ""; for (String str : words) { if (isExists(str) && str.length() > len) { result = str; len = str.length(); } else if (isExists(str) && str.length() == len) { if (result != "") { if (isMin(str, result)) { result = str; } } } } return result; } /** * 判斷str是否小於str2 * @param str 新遇到的等長字串 * @param str2 上一次的最長字串 * @return true:str中的字元小於str2 */ public boolean isMin(String str, String str2){ for (int i=0; i<str.length(); i++) { if (str.charAt(i) < str2.charAt(i)) { return true; } else if (str.charAt(i) == str2.charAt(i)) { continue; } else { return false; } } return false; } /** * 判斷當前字串在陣列中是否是一個個字元慢慢累加起來的 * @param str * @return */ public boolean isExists(String str) { String ss = ""; for (char ch : str.toCharArray()) { ss += ch; if (!map.containsKey(ss)) { return false; } } return true; }
03 第二種解法
在第一種解法中,並沒有用到HashMap中的value值,因此可以使用HashSet來儲存陣列中的單詞。其次,也可以通過陣列排序的方式,省去後續迴圈中判斷最長長度相等的情況,也省去了比較兩個字串誰更小的判斷,更加的簡潔。
Set<String> set = new HashSet<String>(); public String longestWord2(String[] words) { Arrays.sort(words); for (String word : words) { set.add(word); } int len = Integer.MIN_VALUE; String result = ""; for (String str : words) { if (isExists2(str) && str.length() > len) { result = str; len = str.length(); } } return result; } public boolean isExists2(String str) { String ss = ""; for (char ch : str.toCharArray()) { ss += ch; if (!set.contains(ss)) { return false; } } return true; }
04 第三種解法
也可以只使用一個迴圈來解決。依舊是陣列排序,使用HashSet儲存陣列中的單詞,但是存入HashSet的操作是在迴圈中進行的,如果當前單詞的長度等於1或者其本身的子串也存在於HashSet中,才存入HashSet,此步驟就相當於第一種解法和第二種解法中判斷當前單詞是否符合題目要求,由一個字元一次次累加得來的。如果當前字元的長度大於結果單詞的長度,就進行賦值更新操作。
public String longestWord3(String[] words) { Set<String> set = new HashSet<String>(); Arrays.sort(words); String result = ""; for (String word : words) { if (word.length() == 1 || set.contains(word.substring(0, word.length()-1))) { if (word.length() > result.length()) { result = word; } set.add(word); } } return result; }
05 第四種解法
我們也可以不借助排序來實現,其實也是對第二種解法的優化。依舊是使用HashSet,也藉助了一個輔助方法isExists2來判斷當前單詞是否符合題目要求,但不同的是,在迴圈中,此判斷只在當前單詞長度大於結果單詞的長度,或者兩者長度相等且新單詞小於結果單詞這兩種情況下進行,而不像第二種解法那樣,每次都去先判斷當前單詞是否符合題目要求,再去比較長度。其中,比較兩個單詞的大小藉助了字串自帶的compareTo方法。
Set<String> set = new HashSet<String>(); public String longestWord4(String[] words) { for (String word : words) { set.add(word); } String result = ""; for (String word : words) { if (word.length() > result.length() || (word.length() == result.length() && word.compareTo(result) < 0)) { if (isExists2(word)) { result = word; } } } return result; } public boolean isExists2(String str) { String ss = ""; for (char ch : str.toCharArray()) { ss += ch; if (!set.contains(ss)) { return false; } } return true; }
06 小結
演算法專題目前已日更超過五個月 ,演算法題文章171 +篇,公眾號對話方塊回覆【資料結構與演算法 】、【演算法 】、【資料結構 】中的任一關鍵詞,獲取系列文章合集。
以上就是全部內容,如果大家有什麼好的解法思路、建議或者其他問題,可以下方留言交流,點贊、留言、轉發就是對我最大的回報和支援!