给定一个长度为 n 的非降序数组和一个非负数整数 k ,要求统计 k 在数组中出现的次数
数据范围:,数组中每个元素的值满足
要求:空间复杂度 ,时间复杂度
要求:空间复杂度 ,时间复杂度
二分查找,参考剑指Offer,但是用的非递归。 public class Solution { public int GetNumberOfK(int[] array,int k){ if(array==null||array.length==0) return 0; int first=getFirstK(array,k,0,array.length-1); int last=getLastK(array,k,0,array.length-1); if(first==-1 ||last==-1){ return 0; } else{ return last-first+1; } } public int getFirstK(int[] array,int k,int start,int end){ while(start<=end){ int mid=(start+end)/2; if(k<array[mid]) end=mid-1; else if(k>array[mid]) start=mid+1; else{ if((mid>0&&array[mid-1]!=k)||mid==0) return mid; else{ end=mid-1; } } } return -1; } public int getLastK(int[] array,int k ,int start,int end){ while(start<=end){ int mid=(start+end)/2; if(k<array[mid]) end=mid-1; else if(k>array[mid]) start=mid+1; else{ if((mid<array.length-1&&array[mid+1]!=k)||mid==array.length-1) return mid; else{ start=mid+1; } } } return -1; } }
/*二分查找,分治递归 */ public class Solution { public int GetNumberOfK(int [] array , int k) { int length = array.length; if(length <=0 || array == null){ return 0; } int num = array[length/2]; int[] arrayLeft; int[] arrayRight; int count = 0; if(num > k){ arrayLeft = Arrays.copyOfRange(array, 0, length/2); count = GetNumberOfK(arrayLeft, k); } if(num < k){ arrayRight = Arrays.copyOfRange(array, length/2+1, length); count = GetNumberOfK(arrayRight, k); } if(num == k){ count++; int leftCount = 0; int rightCount = 0; int leftNum; int rightNum; for(int i = 1; i <= length/2; i++){ leftNum = array[length/2-i]; if(leftNum==k){ leftCount++; }else{ break; } } count += leftCount; for(int i = 1; i <= length/2-1;i++){ rightNum = array[length/2+i]; if(rightNum==k){ rightCount++; }else{ break; } } count += rightCount; } return count; } }
class Solution { private: int binaryFind(vector<int> &data, int begin, int end ,int k){ int ind = -1; if(begin >= end) return -1; int mid = (end + begin) / 2; if(k == data[mid]) return mid; if((ind = binaryFind(data,begin,mid,k)) != -1) return ind; if((ind = binaryFind(data,mid+1,end,k)) != -1) return ind; return -1; } public: int GetNumberOfK(vector<int> data ,int k) { int ind = binaryFind(data,0,data.size(),k); if(ind == -1) return 0; int pos = ind; int cnt = 1; while(--pos >= 0 && k == data[pos]) ++cnt; while(++ind < data.size() && k == data[ind]) ++cnt; return cnt; } };
该题如果用python来解的话方法可以使用python提供的函数直接求得 也可以避开库函数,使用自己的方法来解 class Solution: # 二分法找到k值的位置 def BinarySearch(self, data, mlen, k): start = 0 end = mlen - 1 while start <= end: mid = (start + end) / 2 if data[mid] < k: start = mid + 1 elif data[mid] > k: end = mid - 1 else: return mid return -1 def GetNumberOfK(self, data, k): # write code here mlen = len(data) # 先使用二分法找到k值的位置 index = self.BinarySearch(data, mlen, k) if index == -1: return 0 # 分别向该位置的左右找 count = 1 for i in range(1,mlen): if index + i < mlen and data[index+i] == k: count += 1 if index - i >= 0 and data[index-i] == k: count += 1 return count
public class Solution { public int GetNumberOfK(int [] array , int k) { if(array.length==0) return 0; int low = 0; int high = array.length-1; int mid = (low+high)/2; int count = 0; while(low<=high){ mid = (low+high)/2; if(array[mid]>k){ high = mid-1; }else if(array[mid]<k){ low = mid+1; }else{ count = 1; int temp = mid-1; while(temp>=0 && array[temp]==array[mid]){ count++; temp--; } temp = mid+1; while(temp<array.length && array[temp]==array[mid]){ count++; temp++; } break; } } return count; } }
/* 先用二分查找找出某个k出现的位置,然后再分别向前和向后查找总的个数*/ class Solution { public: int GetNumberOfK(vector<int> data ,int k) { int i = binaryFind(data,0,data.size(),k); if( i == -1) return 0; int sum = 1; for(int j = i - 1; j >= 0; j--){ if(data[j] == k) sum++; else break; } for(int j = i + 1; j < data.size(); j++){ if(data[j] == k) sum++; else break; } return sum; } int binaryFind(vector<int> &data, int begin, int end ,int k){ if(begin >= end) return -1; int mid = (begin + end) / 2; if(data[mid] == k) return mid; int res = -1; if((res = binaryFind(data,begin,mid,k)) != -1) return res; if((res = binaryFind(data,mid + 1, end,k) != -1)) return res; return -1; } };
//因为data中都是整数,所以可以稍微变一下,不是搜索k的两个位置,而是搜索k-0.5和k+0.5 //这两个数应该插入的位置,然后相减即可。 class Solution { public: int GetNumberOfK(vector<int> data ,int k) { return biSearch(data, k+0.5) - biSearch(data, k-0.5) ; } private: int biSearch(const vector<int> & data, double num){ int s = 0, e = data.size()-1; while(s <= e){ int mid = (e - s)/2 + s; if(data[mid] < num) s = mid + 1; else if(data[mid] > num) e = mid - 1; } return s; } };
public int GetNumberOfK(int[] array , int k) { if(array == null || array.length == 0) return 0; int l = 0, r = array.length-1; int count = 0; while(l <= r){ int mid = (l+r) >> 1; if(array[mid] < k){ l = mid + 1; }else if(array[mid] > k){ r = mid - 1; }else{ count++; l = mid-1; r = mid+1; while(l >= 0 && array[l] == k){ count++; l--; } while(r < array.length && array[r] == k){ count++; r++; } break; } } return count; }
# -*- coding:utf-8 -*- # 时间复杂度O(logn),我的方法不用找最前和最后的k,是递归中直接计算k的个数 class Solution: def GetNumberOfK(self, data, k): if not data: return 0 return self.helper(data,k) def helper(self,data,k): if not data: return 0 left, right = 0, len(data) - 1 mid = (left + right) // 2 if data[mid] > k: return self.helper(data[:mid], k) elif data[mid] < k: return self.helper(data[mid + 1:], k) else: return 1 + self.helper(data[:mid], k) + self.helper(data[mid + 1:], k)
a)若中点已经是数组第一个元素,则直接返回中点位置;
b)若中点值的前一个元素和中点值不同,则直接返回中点位置;
c)若中点值前一个元素和中点值相同,则继续在前半段找;
public int GetNumberOfK(int [] array , int k) {
// 若序列最小值大于k、最大值小于k,则k不存在!
if ( array==null || array.length<=0 || k < array[0] || k > array[array.length-1] ) return 0;
int firstK = GetFirstK( array, 0, array.length-1, k );
int lastK = GetLastK( array, 0, array.length-1, k );
if ( firstK==-1 || lastK==-1 ) return -1;
return (lastK-firstK)+1;
}
private int GetFirstK( int[] array, int start, int end, int k ) {
if ( start > end ) return -1;
int mid = ( start+end ) >> 1;
if ( k < array[mid] ){
end = mid-1;
}
else if ( k > array[mid] ){
start = mid + 1;
}
else {
if ( mid==0 || array[mid-1]!=array[mid] ) {
return mid;
}
else {
end = mid-1;
}
}
return GetFirstK( array, start, end, k );
}
private int GetLastK( int[] array, int start, int end, int k ) {
if ( start > end ) return -1;
int mid = ( start+end ) >> 1;
if ( k < array[mid] ){
end = mid-1;
}
else if ( k > array[mid] ){
start = mid + 1;
}
else {
if ( mid==array.length-1 || array[mid+1]!=array[mid] ) {
return mid;
}
else {
end = mid+1;
}
}
return GetLastK( array, start, end, k );
}
};
//使用STL算法count 循序查找O(n)
int GetNumberOfK(vector<int> data, int k) {
return count(data.begin(), data.end(), k);
}
//利用STL的multimap容器底层以红黑树为基础,构造成本O(n),查询成本O(log n) int GetNumberOfK(vector<int> data, int k) { multiset<int> msData(data.begin(), data.end()); return msData.count(k); }
//利用STL库函数lower_bound()和upperBound(),O(log n) int GetNumberOfK(vector<int> data ,int k) { auto iter1 = lower_bound(data.begin(), data.end(), k); auto iter2 = upper_bound(data.begin(), data.end(), k); return static_cast<int>(iter2 - iter1); }
public int GetNumberOfK(int[] array, int k) { int l, r, m, l1, r1; for (l = 0, r = array.length - 1, m = (l + r) >> 1; l < m; m = (l + r) >> 1) if (k <= array[m]) r = m; else l = m + 1; for (l1 = 0, r1 = array.length - 1, m = (l1 + r1) >> 1; l1 < m; m = (l1 + r1) >> 1) if (k < array[m]) r1 = m - 1; else l1 = m; return r > -1 && array[l] == k ? r1 - l + 1 : 0; }
public int GetNumberOfK(int[] array, int k) { if (array == null || array.length == 0) return 0; int t = getFirst(array, 0, array.length - 1, k); if (t != -1) return getLast(array, 0, array.length - 1, k) - t + 1; return 0; } int getFirst(int[] array, int s, int e, int k) { if (s >= e) return array[s] == k ? s : -1; int m = (s + e) / 2; if (array[m] < k) return getFirst(array, m + 1, e, k); else return getFirst(array, s, m, k); } int getLast(int[] array, int s, int e, int k) { if (s >= e) { if (array[s] == k) return s; return array[s - 1] == k ? s - 1 : -1; } int m = (s + e) / 2; if (array[m] <= k) return getLast(array, m + 1, e, k); else return getLast(array, s, m, k); }
//这题就用二分先找到一个,再判断前面和后面的数是不是也为目标值就行了 int GetNumberOfK(vector<int> data ,int k) { if(data.size()==0) return 0; int l =0,n=data.size()-1; while(l<=n) { int mid = (l+n)/2; if(data[mid]==k) { int count =0; int m=mid; while(mid>=0&&data[mid]==k)//判断前一个是否为目标值(注意防止数组越界) { count+=1; mid--; } while(m+1<=n&&data[m+1]==k)//判断后一个是否为目标值(注意防止数组越界) { count++; m++; } return count; } if(data[mid]>k) { n=mid-1; } else{ l=mid+1; } } return 0; }
int find(int*data,int len,int k,int flag) { int left=0,right=len-1,mid; while(left<=right){ mid=left+(right-left)/2; if(data[mid]>k) right=mid-1; else if(data[mid]<k) left=mid+1; else{ if(flag==0){//flag==0,找最左边数字, if(mid==left ||data[mid-1]!=k) return mid; else right=mid-1;//把中心向左推 }else { if(mid==right||data[mid+1]!=k) return mid; else left=mid+1; } } } return -1; } int GetNumberOfK(int* data, int dataLen, int k ) { // write code here if(dataLen==0) return 0; int left=find(data,dataLen,k,0); int right=find(data,dataLen,k,1); if(left==-1&&right==-1) return 0;//没找到 return right-left+1; }
public class Solution { public int GetNumberOfK(int [] array , int k) { // 二分法: // return binary1(array,k+1)-binary1(array,k); return binary2(array,k+1)-binary2(array,k); } // 二分查找模板1 public int binary1(int [] array , int k){ int left = 0; // 如果区间定义的是左闭右闭 int right = array.length-1; // while里必须用等号 while(left<=right){ // 这么写可以防溢出? int mid = left + ((right-left)>>1); // 这里的=是由题目而定的,本题中我们想求左边界,所以在=的情况下也左移right if(array[mid]>=k){ // right这里必须-1 right = mid -1; }else{ left = mid + 1; } } return left; } // 二分查找模板2 public int binary2(int [] array , int k){ int left = 0; // 如果区间定义的是左闭右开 int right = array.length; // while里不可以用等号 while(left<right){ // 这么写可以防溢出? int mid = left + ((right-left)>>1); // 这里的=是由题目而定的,本题中我们想求左边界,所以在=的情况下也左移right if(array[mid]>=k){ // right 这里不可-1 right = mid ; }else{ left = mid + 1; } } return left; } }