給出兩個單詞,找到它們的最短距離 (以它們之間隔了多少個單詞計數)。

  • 有一篇文章內含多個單詞,現給定兩個單詞,請設計一個高效算法,找出文中這兩個單詞的最短距離(即最少相隔的單詞數,也就是兩個單詞在文章中位置的差的絕對值)。
  • 給定一個string數組article,表明所給文章,同時給定文章的單詞數n和待查找的兩個單詞x和y。請返回兩個單詞的最短距離。保證兩個單詞均在文中出現且不相同,同時保證文章單詞數小於等於1000。
  • 代碼以下
public class Distance {
    public int getDistance(String[] s, int n, String x, String y) {
        //兩個單詞均在文中出現且不相同      
        int startX=-1, endY = -1;//1和0之間間隔爲1
        int minD = Integer.MAX_VALUE;

        for(int i=0; i<s.length; i++){
            if(s[i].equals(x)) startX=i;
            else if(s[i].equals(y)) endY=i;
            else continue;
//兩個元素的距離:startX-endY的絕對值,與當前記錄的最小間距minD比,取小的               
            if(startX!=-1 && endY!=-1) minD=Math.min(Math.abs(startX-endY), minD);
        }
        return minD;
    }
}

 

若是隻要找一次就用第一種O(n)解法java

若是要找屢次就多用一個Hashtable,把全部的組合都保存起來面試

 

 

 

[java] view plain copy算法

在CODE上查看代碼片派生到個人代碼片

  1. package Hard;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.HashSet;  
  5. import java.util.Map;  
  6.   
  7. import CtCILibrary.AssortedMethods;  
  8.   
  9.   
  10. /** 
  11.  * You have a large text file containing words. Given any two words, find the shortest distance (in terms of number of words) between them in the file. Can you make the searching operation in O(1) time? What about the space complexity for your solution? 
  12.  
  13. 譯文: 
  14.  
  15. 有一個很大的文本文件,裏面包含許多英文單詞。給出兩個單詞,找到它們的最短距離 (以它們之間隔了多少個單詞計數)。你能在O(1)的時間內返回任意兩個單詞間的最短距離嗎? 你的解法空間複雜度是多少? 
  16.  * 
  17.  */  
  18. public class S18_5 {  
  19.   
  20.     // O(n)  
  21.     public static int shortest(String[] words, String word1, String word2) {  
  22.         int min = Integer.MAX_VALUE;  
  23.         int lastPosWord1 = -1;  
  24.         int lastPosWord2 = -1;  
  25.         for (int i = 0; i < words.length; i++) {  
  26.             String currentWord = words[i];  
  27.             if (currentWord.equals(word1)) {  
  28.                 lastPosWord1 = i;  
  29.                 // Comment following 3 lines if word order matters  
  30.                 int distance = lastPosWord1 - lastPosWord2;  
  31.                 if (lastPosWord2 >= 0 && min > distance) {  
  32.                     min = distance;  
  33.                 }  
  34.             } else if (currentWord.equals(word2)) {  
  35.                 lastPosWord2 = i;  
  36.                 int distance = lastPosWord2 - lastPosWord1;  
  37.                 if (lastPosWord1 >= 0 && min > distance) {  
  38.                     min = distance;  
  39.                 }  
  40.             }  
  41.         }  
  42.         return min;  
  43.     }  
  44.   
  45.     //===============================================================================  
  46.     private static Map<HashSet<String>, Integer> distances =   
  47.             new HashMap<HashSet<String>, Integer>();  
  48.        
  49.     public static int query(String word1, String word2) {  
  50.           
  51.         HashSet<String> pair = new HashSet<String>();  
  52.         pair.add(word1);  
  53.         pair.add(word2);  
  54.         if(distances != null && distances.containsKey(pair)){  
  55.             return distances.get(pair);  
  56.         }  
  57.         return Integer.MAX_VALUE;  
  58.           
  59.     }  
  60.       
  61.     public static void buildMap(String[] wordlist) {  
  62.         // build the mapping between pairs of words to  
  63.         // their shortest distances  
  64.         for (int i = 0; i < wordlist.length; ++i) {  
  65.             for (int j = i + 1; j < wordlist.length; ++j) {  
  66.                 if (!wordlist[i].equals(wordlist[j])) {  
  67.                     HashSet<String> pair = new HashSet<String>();  
  68.                     pair.add(wordlist[i]);  
  69.                     pair.add(wordlist[j]);  
  70.                     if (distances.keySet().contains(pair)) {  
  71.                         int curr = distances.get(pair);  
  72.                         if (j - i < curr)  
  73.                             distances.put(pair, j - i);  
  74.                     } else {  
  75.                         distances.put(pair, j - i);  
  76.                     }  
  77.                 }  
  78.             }  
  79.         }  
  80.     }  
  81.       
  82.       
  83.       
  84.     public static void main(String[] args) {  
  85.         String[] wordlist = AssortedMethods.getLongTextBlobAsStringList();  
  86.         System.out.println(AssortedMethods.stringArrayToString(wordlist));  
  87.   
  88.         String[][] pairs = { { "Lara", "the" }, { "river", "life" },  
  89.                                   { "path", "their" }, { "life", "a" } };  
  90.           
  91.         buildMap(wordlist);  
  92.           
  93.         for (String[] pair : pairs) {  
  94.             String word1 = pair[0];  
  95.             String word2 = pair[1];  
  96.             int distance = shortest(wordlist, word1, word2);  
  97.             System.out.println("Distance between <" + word1 + "> and <" + word2 + ">: " + distance + ", " + query(word1, word2));  
  98.         }  
  99.     }  

 

題目

有一個很大的文本文件,裏面包含許多英文單詞。給出兩個單詞,找到它們的最短距離 (以它們之間隔了多少個單詞計數)。你能在O(1)的時間內返回任意兩個單詞間的最短距離嗎? 你的解法空間複雜度是多少?數組

解答

先看一個例子,爲了簡單起見,咱們假設文件裏就只有如下兩句話。而後, 咱們如今來求is和name的最短距離。假設相鄰的兩個單詞距離爲1。app

 

1函數

2ui

What is your name My name is Hawsteinspa

 

 

首先,咱們遇到的第一個問題是:是否要考慮順序?咱們求的是is和name間的距離, 那麼文本中先出現name再出現is的狀況要不要算進來。這一點是要和麪試官進行交流確認的。 這裏咱們假設不考慮順序,而且認爲本文中只有單詞,沒有標點。 爲了進一步簡化問題,咱們能夠用一個字符串數組來保存單詞, 接下來考慮如何計算兩個單詞間的最短距離。.net

最直觀的一個解法是,遍歷單詞數組,遇到is或name就更新它們的位置, 而後計算is和name之間的距離,若是這個距離小於以前的最小距離,則更新這個最小距離。 看圖示:設計

 

1

2

3

4

What is your name My name is Hawstein

0    1  2    3    4  5    6  7

                  p

 

 

p表示遍歷的當前位置。此時已經通過了前面的一個is和name,is位置爲1,name位置爲3, 最小距離min=3-1=2。當p移動到下一個單詞,發現是name,則更新name的位置爲5, 減去is的位置1獲得4,並不小於min,不更新,繼續。當p移動到is,更新is的位置爲6, 減去name的位置5,獲得距離爲1,小於min,更新min=1。p以後一直移動到末尾, 沒遇到is或name,再也不更新。最後返回最小值min。時間複雜度O(n),空間複雜度O(1)。

代碼以下:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

int ShortestDist(string text[], int n, string word1, string word2){

    int min = kMaxInt / 2;

    int pos1 = -min;

    int pos2 = -min;

 

    for(int pos=0; pos<n; ++pos){

        if(text[pos] == word1){

            pos1 = pos;

            int dist = pos1 - pos2;

            if(dist < min)

                min = dist;

        }

        else if(text[pos] == word2){

            pos2 = pos;

            int dist = pos2 - pos1;

            if(dist < min)

                min = dist;

        }

    }

 

    return min;

}

 

題目要求在O(1)的時間內返回兩個單詞的最短距離,上述代碼確定是沒法知足要求的。 那要怎麼作呢?只能用哈希表作預處理了,空間換時間。

方法一

遍歷一次文本,用哈希函數將每一個單詞映射到不一樣結點,結點後保存該單詞出現的位置。 好比對於上面的例子

 

1

2

3

What is your name My name is Hawstein

0    1  2    3    4  5    6  7  

 

 

遍歷一次並處理後,咱們獲得每一個單詞在文本中出現的位置:(哈希值是隨便寫的,示意用)

 

1

2

3

4

5

6

7

8

單詞    哈希值   出現位置

What:     3       0

is:       7       1, 6

your:     13      2

name:     14      3, 5

My:       25      4

Hawstein: 27      7

 

 

求兩個單詞間的最小距離時,首先用O(1)時間經過哈希函數映射到指定結點, 而後對於其中一個單詞的每一個位置,去與第二個單詞的全部位置比較,找到最小的差值。 因爲位置是遞增的,所以能夠修改二分查找進行搜索。

該方法的平均查找複雜度應該是O(1)的,但最壞狀況下沒法保證O(1)的查找時間, 考慮一種極端狀況,文本中的單詞就只有is和name,它們的數量各爲(½)n, 使用這種算法,咱們須要O(nlogn)的時間。

方法二

預處理階段把文本中任意兩個單詞間的最小距離計算出來, key是兩個單詞鏈接後的哈希值,value保存的就是最小距離。 查找階段就只須要把兩個單詞鏈接求其哈希值,而後直接返回其對應的value便可。 查找兩個單詞的最小距離時間複雜度O(1)。須要O(n2 )的時間來作預處理。

因爲咱們是不考慮順序的,所以作兩個單詞的鏈接時,不能直接鏈接, 這樣會致使is和name鏈接後是isname,而name和is鏈接後nameis, 它們的哈希值不同,這並非咱們想要的。所以,在作兩個單詞的鏈接時, 咱們可讓第一個字符較小的單詞放在前面(反正定義一個規則來保證鏈接的惟一性便可)。 好比對於name和is,因爲在字典序中,i<n,因此鏈接是isname。

仍是用上面的例子,預處理後獲得:(哈希值是隨便寫的數字,示意用)

 

1

2

3

4

5

6

7

8

單詞鏈接      哈希值   最小距離

(isWhat)     8       1

...          ...     ...

(isname)     12      1

...          ...     ...

(isMy)       33      2

...          ...     ...

 

 

這樣當我要求is和name之間的最小距離時,就只須要先鏈接它們獲得isname, 而後用哈希函數求出isname的哈希值12,而後直接返回它對應的最小距離便可。

若是有衝突怎麼辦?即兩個不一樣的字符串映射到同一個哈希值,咱們能夠用鏈地址法, 把衝突的鏈接字符串連接起來,這樣每一個結點就須要保存鏈接字符及其對應的最小距離。 好比對於上面的例子,假設isname和isMy的哈希值相同,咱們能夠按以下所示去作:

 

1

2

3

4

5

6

哈希值   最小距離

8       (isWhat,1)

...     ...

12      (isname,1) -> (isMy,2)

...     ...

 

 

這樣一來,當咱們求得一個鏈接字符串str的哈希值是12, 就依次去與其後面的結點作比較。若是str等於isname,返回1;不然,移動到下一個結點, 繼續比較。若是str等於isMy,返回2。

方法三

也能夠先將兩個單詞分別映射到兩個哈希值,好比is映射到哈希值i,name映射到哈希值j, 而後將它們的最小距離保存在d[i][j]中。這裏因爲是不考慮單詞順序的,所以, 咱們能夠將較小的哈希值放在d的第一維,較大的放在第二維。也就是對於d[i][j], 有i<j。一樣,這種方法也要考慮衝突問題。

 

解法1:咱們假設單詞word1和word2誰在前誰在後可有可無。要解決此題,咱們須要遍歷一次這個文件。在遍歷期間,咱們會記下最後看見word1和word2的地方,並把它們的位置存入lastPosWord1和lastPosWord2中。碰到word1時,就拿他跟lastPosWord2比較,若有必要則更新min,而後更新lastPosWord1.每碰到word2時,咱們也執行一樣的操做。遍歷結束後,就能夠獲得最短距離。

實現算法:

int ShortestDist(string text[], int n, string word1, string word2){
    int min = kMaxInt / 2;
    int pos1 = -min;
    int pos2 = -min;

    for(int pos=0; pos<n; ++pos){
        if(text[pos] == word1){
            pos1 = pos;
            int dist = pos1 - pos2;
            if(dist < min)
                min = dist;
        }
        else if(text[pos] == word2){
            pos2 = pos;
            int dist = pos2 - pos1;
            if(dist < min)
                min = dist;
        }
    }

    return min;
}

若是上述代碼要重複調用(查詢其餘單詞對的最短距離),能夠構造一個散列表,記錄每一個單詞及其出現的位置。而後,咱們只需找到listA和listB中(算術)差值最小的那兩個值。

hash_map<string,vector<int> > listA;

hash_map<string,vector<int> > listB;

listA:{1,2,9,15,25}

listB:{4,10,19}

相關文章
相關標籤/搜索