題目:一個單詞單詞字母交換,可得另一個單詞,如army->mary,成為兄弟單詞。提供一個單詞,在字典中找到它的兄弟。描述數據結構和查詢過程。
解法一:使用hash_map和鏈表
(1)首先定義一個key,使得兄弟單詞有相同的key,不是兄弟的單詞有不同的key。例如,將單詞按字母從小到大重新排序后作為其key,比如bad的key為abd,good的key為dgoo。
(2)使用鏈表將所有兄弟單詞串在一起,hash_map的key為單詞的key,value為鏈表的起始地址。
(3)開始時,先遍歷字典,將每個單詞都按照key加入到對應的鏈表當中。
(4)當需要找兄弟單詞時,只需求取這個單詞的key,然后到hash_map中找到對應的鏈表即可。
這樣創建hash_map時時間復雜度為O(n),查找兄弟單詞時時間復雜度是O(1)。
解法二:同樣使用hash_map和鏈表
(1)將每一個字母對應一個質數,然后讓對應的質數相乘,將得到的值進行hash,這樣兄弟單詞的值就是一樣的了,並且不同單詞的質數相乘積肯定不同。
(2)使用鏈表將所有兄弟單詞串在一起,hash_map的key為單詞的質數相乘積,value為鏈表的起始地址。
(3)對於用戶輸入的單詞進行計算,然后查找hash,將鏈表遍歷輸出就得到所有兄弟單詞。
這樣創建hash_map時時間復雜度為O(n),查找兄弟單詞時時間復雜度是O(1)。
如果是海量詞典的話,可以用B+樹。。。。。
注:上述兩種方法是比較高效的算法,一下介紹一種普通方法:
解法三:全排列,然后依次比較
看到這個題目后,直覺是可能是這樣的:求出輸入單詞的全部變換(假如單詞的長度是n,則其全部變換有n!個。如果有相同的字母就不是n!了),求出單詞的變換后,判斷每個變換是否在字典中。例如對於輸入abc,則其變換有3!=6種:abc、acb、bca、bac、cab、cba。然后在依次判斷這6個單詞(當然這里不是單詞了,而是字符串)是否在字典中,如果在字典中則記錄下來。
很明顯這種思想的復雜度是比較高的,因為對於n稍微大點的話,n!是一個很可怕的遞增過程,因此這個方法是不太可取的。
以下是全排列代碼:
/** * @param src * @param start 起始位置索引 * @param end 結束位置索引 */ public static void perm(String[] src,int start,int end){ if(start==end){//當只要求對數組中一個字母進行全排列時,只要按該數組輸出即可 for(int i=0;i<=end;i++){ System.out.print(src[i]); } System.out.println(); } else{//多個字母全排列 for(int i=start;i<=end;i++){ String temp=src[start];//交換數組第一個元素與后續的元素 src[start]=src[i]; src[i]=temp; perm(src,start+1,end);//后續元素遞歸全排列 temp=src[start];//將交換后的數組還原 src[start]=src[i]; src[i]=temp; } } }
將字典中的和‘比較單詞’首字母相同的單詞取出存放到一個數組中,將每一個組合和字典中的單詞比較。首先比較單詞長度,長度相同,則繼續比較;否則,比較下一個單詞。算法如下:
/** * @param src 字典中的單詞 * @param des 要比較的單詞,因為要做大量比較,所以轉化為字符數組 * @return */ public static boolean compare(String src,String[] des){ int len = src.length(); if(len != des.length){//如果長度不相等,肯定不是兄弟單詞,則無需比較 return false; } int i = 1;//i等於1是因為首字符已經相同,無需比較 while(i<len){ if(des[i].equals(String.valueOf(src.charAt(i)))){ i++; continue; } return false; } return true; }