题目描述
统计一个数字在排序数组中出现的次数。
思路:
仍然使用二分查找思想,尝试不使用两边扫描,便能找到第一个k和最后一个k
分析:当有数字和K相等时,我们先判断这个数字是不是第一个k。如果中间数字的前面一个数字不是K,则此时中间的数字刚好就是第一个k,同理,如果中间数字的后面一个数字不是K,那么中间的数字就是最后一个k
因为GetFirstK和GetLastK都是利用二分查找,所以总的时间复杂度O(logn)
代码:
class Solution {
public:
int GetNumberOfK(vector<int> data ,int k) {
int n=data.size();
int number=0;
if(n>0)
{
int first=GetFirstK(data,k,0,n-1);
int last=GetLastK(data,k,0,n-1);
if(first>-1&&last>-1)
number=last-first+1;
}
return number;
}
//第一个k的位置
int GetFirstK(vector<int> data ,int k,int low,int high) {
if(low>high)
return -1;
int mid=(low+high)/2;
if(k==data[mid])
{
if((mid>0&&data[mid-1]!=k)||mid==0)
return mid;
else
high=mid-1;
}
else if(k>data[mid])
low=mid+1;
else high=mid-1;
return GetFirstK(data,k,low,high);
}
//最后一个k的位置
int GetLastK(vector<int> data ,int k,int low,int high) {
if(low>high)
return -1;
int mid=(low+high)/2;
if(k==data[mid])
{
if((mid<data.size()-1&&data[mid+1]!=k)||mid==data.size()-1)
return mid;
else
low=mid+1;
}
else if(k>data[mid])
low=mid+1;
else high=mid-1;
return GetLastK(data,k,low,high);
}
};
举一反三:
0~n-1中缺失的数字
一个长度为n-1的递增顺序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
思路一:
算出当前数组的数组和s1,和数字0~n-1之间的数字和(n(n-1)/2)s2,利用s2-s1就是不在数组中的数字。
时间复杂度O(N)
思路二:
1、由于数组是递增的,且每个数字都是在0~n-1之内,所以在不缺少任何数字的情况下,元素值和下标值应该是相等的。
2、记不在数组中的数字为m,则所有比m小的数字的下标都与他们的值相同,比m大的值下标都与其值相差1.
3、因此问题转化为找出数组中第一个元素值与其下标不相等的元素。
代码:
int GetMissingNumber(vector<int>num)
{
int n=num.size();
if(n==0)
return -1;
int left=0;
int right=n-1;
while(left<=right)
{
int mid=(left+right)/2;
if(num[mid]!=middle)
{ if(middle===0||num[mid-1]==mid-1)
return mid;
right=mid-1;
}
else left=mid+1;
}
if(left==n)
return n;
//无效输入,数组没有按照要求排序,或者有数字不在0~n-1范围之内
return -1;
}
数组中数值和下标相等的元素
假设一个单调递增的数组里的每个元素都是整数并且是唯一的。请编程实现一个函数,找出数组中任意一个数值等于其下标的元素。例如:在数组{-3,-1,1,3,5}中,数字3和它的下标相等。
思路:
由上一题得到启发,我们可以先分析数组{-3,-1,1,3,5},我们发现,元素值与其下标的差是递增且过0的,-3,-2,-1,0,1,当差值等于零时,就是我们想要的值。
因此,我们根据差值与0比较利于二分法找出元素值与下标相同的值。
代码:
int GetNumberSameAsIndex(vector<int>num)
{
int n=num.size();
if(n==0)
return -1;
int left=0;
int right=n-1;
while(left<=right)
{
int mid=(left+right)/2;
if(num[mid]-mid>0)
right=mid-1;
else if(num[mid]-mid<0)
left=mid+1;
else return mid;
}
return -1;
}