题目
统计一个数字在排序数组中出现的次数。
分析
第一反应是用HashMap记录下数组中每个数字,和他们出现的次数,最后返回数字k的次数即可。
然而如果面试考到这个题的话,既然说了是排序数组,面试官应该不是想考遍历这么简单,应该是考“二分查找”的。
所以,此题应该用“二分查找”找到k第一次出现的位置,和k最后一次出现的位置,然后返回lastK-firstK+1。
代码1
import java.util.HashMap;
public class Solution {
public int GetNumberOfK(int [] array , int k) {
//用HashMap记录下数组中每个数字,和他们出现的次数,最后返回数字k的次数即可
HashMap<Integer,Integer> map = new HashMap<>();
for(int i=0; i<array.length; i++){
if(map.containsKey(array[i])){//出现过
int value = map.get(array[i]);
map.put(array[i], ++value); //次数加一
}else{
map.put(array[i], 1);
}
}
if(map.containsKey(k)){ //k在数组中出先过
return map.get(k);
}
return 0; //k没有出现过
}
}
代码2
import java.util.HashMap;
public class Solution {
public int GetNumberOfK(int [] array , int k) {
//“二分查找”获取到k所在的第一个位置,以及k所在的最后一个位置,然后返回lastK-firstK+1
if(array==null || array.length==0){
return 0;
}
int firstK = getFirstK(array, k, 0, array.length-1);
int lastK = getLastK(array, k, 0, array.length-1);
if(firstK == -1){ //k不存在
return 0;
}
return lastK-firstK+1;
}
public int getFirstK(int[] array, int k, int start, int end){
while(start <= end){
int mid = (start+end)/2;
if(array[mid] < k){ //k在mid和end之间
start = mid+1;
}else if(array[mid] > k){ //k在start和mid之间
end = mid-1;
}else{
//中间的数等于k,这里有两种情况:
//(1)若左边还有等于k的数,则第一个k还是出现在左边
//(2)若左边没有等于k的数了,则第一个k就在mid位置
if(mid-1>=start && array[mid-1]==k){
end = mid-1;
}else{
return mid;
}
}
}
return -1;
}
public int getLastK(int[] array, int k, int start, int end){
while(start <= end){
int mid = (start+end)/2;
if(array[mid] < k){ //k在mid和end之间
start = mid+1;
}else if(array[mid] > k){ //k在start和mid之间
end = mid-1;
}else{
//中间的数等于k,这里有两种情况:
//(1)若右边还有等于k的数,则最后一个k还是出现在右边
//(2)若右边没有等于k的数了,则最后一个k就在mid位置
if(mid+1<=end && array[mid+1]==k){
start = mid+1;
}else{
return mid;
}
}
}
return -1;
}
}