java 程序员面试金典 3

时间:2021-10-25 11:41:11
1   请设计一个高效的方法,找出任意指定单词在一篇文章中的出现频数。

给定一个string数组article和数组大小n及一个待统计单词word,请返回该单词在文章中的出现频数。

   保证文章的词数小于等于1000。

//法1  :常规对比做法(我的做法)
//也想过 用map等集合来统计 ,但是这个查找数据量不大,没必要
import java.util.*;
public class Frequency{
public int getFrequency (String [] article,int n,String word){
int count=0;
for(int i=0;i<n;i++){
if(article[i].equals(word)) //字符串比较值相等时用equals.
count++;
}
return count;
}
}

//法2  //为了节省时间,首先比较目标词和文章中的词汇长度是否相同,若相同,再进一步比较是否是同一个词,//从string数组第一个遍历,就可以检查出来了,因为比较是逐个字母比较,所以长度不同直接排除,//可以节省不少时间。 public int getFrequency(String [] article,int n,String word){   int i=0,num=0;   while(i<n){       if(article[i].length()==word.length())             if(article[i].equals(word)){                   num++;             }       i++;   }    return num; }
法3 :

注意:这个方法只适用于字符串,不适用于结构体这种对象,这种方法也比较消耗内存,字符串上的效率是极高的,比map、手写红黑树等好多了,还容易实现。
查询次数只有一次,让这个方法看着太呆萌了——复杂度是O(n*length+length),在这种情况下和暴力没什么区别。
但是如果是查询q次,这种方法的复杂度是O(n*length+q*length),比暴力的O(n*q*length)好多了。
这里选用的数据结构,叫字典树(Trie)。插入和查找的时间复杂度只取决于你的当前单词的长度O(length)。
但是Trie比较消耗内存,怎么办?
搜索引擎实现的时候,一种变通方法是,借用二叉搜索树的思路实现一个三叉Trie——其中查询串中当前字符比指向的节点字符小的时候,去左儿子,大的时候去右儿子,相等的时候则向下走一层。
统计一个单词出现的次数?这个在Trie上很简单。插入的时候,每个节点新增一个count域,记录以这个节点为结尾的单词数有几个,就好了。
代码如下:
import java.util.*;
public class Frequency {
    public int getFrequency(String[] article, int n, String word) {
        if(n <= 0 || word == null || word.length() == 0){
            return 0;
        }
         
        TrieNode root = new TrieNode();
        for(String str : article) {
            root.insert(str, 0);
        }
         
        TrieNode ans = root.search(word, 0);
        if(ans != null && ans.isWord == true) {
            return ans.cnt;
        }
        return 0;
         
    }
}
 
class TrieNode {
    private TrieNode[] children;
    public boolean isWord;
    public int cnt;

public TrieNode() {
children = new TrieNode[52];
isWord = false;
cnt = 0;
}

public void insert(String word, int index) {
if(index == word.length()) {
isWord = true;
++cnt;
return;
}
int c = word.charAt(index) - 'a';
if(children[c] == null) {
children[c] = new TrieNode();
}

children[c].insert(word, index + 1);
}

public TrieNode search(String word, int index) {
if(index == word.length()) {
return this;
}

int c = word.charAt(index) - 'a';
if(children[c] == null) {
return null;
}
return children[c].search(word, index + 1);
}
}

2. 请设计一个高效算法,找出数组中两数之和为指定值的所有整数对。
    给定一个int数组A和数组大小n以及需查找的和sum,请返回和为sum的整数对的个数。保证数组大小小于等于3000。

//法1 :(我的方法)常规循环做法  时间复杂度为O(n*n);
import java.util.*;
public class FindPair{
public int countPairs(int [] A,int n,int sum){
//常规遍历数组求和
int num=0;
for(int i=0;i<n;i++){
for(intj=i+1; j<n;j++){
if(A[i]+A[j]==sum)
num++;
}
}
return num;
}
}

//法2 :(我自己有思路,但是没有考虑到重复数字的情况,出现错误) //将数组排序之后  用前后两个指针去往中间夹  就是需要注意存在相同元素的情况  //往中间夹 begin和end不同时  若两边分别存在重复的数字  2 2 3 3 则两者数目相乘为配对数量2*2=4种//若begin和end指向的数字是相同的数  如2 2 2 2   则可能配对数量为C(4,2)=4*(4-1)/2; import java.util.*;public class FindPair{   public int countPairs(int [] A,int n,int sum){       int start=0,end=n-1,count=0;       Arrays.sort(A);       while(start<end){          if(A[start] +A[end]<sum)              start++;          else if(A[start]+A[end]>sum)              end--;          else{              if(A[start]==A[end]){                 int t=end-start+1;                 count+=(t*(t-1)/2);                 break;              }else{                 int left=start+1;                 int right=end-1;                 int countLeft=1;                 int countRight=1;                 while(A[left]==A[start]){                      countLeft++;                      left++;                 }                 while(A[right]==A[end]){                      countRight++;                      end--;                 }                 count+=(countLeft*countRight);                 start=left;                 end=right;              }           }       }      return count;    }}
//法3 :看到其他博客里的思路 //用哈希表来解决import java.util.*;public class FindPair{   public int countPairs(int [] A, int n,int sum){      HashMap<Integer,Integer> hm=new HashMap<Integer,Integer>();   //创建一个hash表      int count=0;        for(int i=0;i<n;i++){         count+=getTimes(hm,sum-A[i]);         hashMap.put(A[i], getTimes(hm, A[i]) +1);      }      return count;   }   private Integer getTimesCount(HashMap<Integer,Integer> hm,Integer word){       Integer time=hm.get(word);       return time==null? 0:time;   }}