给出两个单词,找到它们的最短距离 (以它们之间隔了多少个单词计数)。

  • 有一篇文章内含多个单词,现给定两个单词,请设计一个高效算法,找出文中这两个单词的最短距离(即最少相隔的单词数,也就是两个单词在文章中位置的差的绝对值)。
  • 给定一个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}

相关文章
相关标签/搜索