剑指offer#53.数字在排序数组中出现的次数 && II. 0~n-1中缺失的数字

数字在排序数组中出现的次数:统计一个数字在排序数组中出现的次数。

思路:因为数组中已经排好序,所以立刻可以想到用二分查找,但是二分查找只能查找到一个数,所以查完以后要向左向右去找出分别的第一个和最后一个k,然后得到次数,这样的复杂度为O(n),因此我们需要改进一下,修改二分查找找出第一个数和最后一个数,就可以使复杂度变成O(logN),如何判断第一个数呢,只要找到的这个数下标是0或者不为0,则与其左边数不一样则就是第一个k了,如果不是找到第一个k,则继续找;如何判断最后一个数呢?只要找到这个数的下标是size()-1或者它的下一个数与它不相等,则说明是最后一个数,不然就继续找。
代码逐次改进

int GetNumberOfK(vector<int> data ,int k) {
        //采用二分查找
        if(data.size() == 0)
            return 0;
        int left = GetCore(data,0,data.size()-1,k,true);
        if(left == -1)return 0;
        int right = GetCore(data,left,data.size()-1,k,false);
        return right-left+1;
    }
    int GetCore1(vector<int>& data,int low,int high,int k){
        int middle;
        while(low <= high){
            middle = low + ((high - low)>>1);
            if(data[middle] == k && (middle == 0 || data[middle-1] != k)){
                //开启找第一个k的判断
                return middle;
            }
            if(data[middle] >= k)
                high = middle - 1;
            else
                low = middle + 1;
        }
        return -1;
    }
    int GetCore2(vector<int>& data,int low,int high,int k){
        int middle;
        while(low <= high){
            middle = low + ((high - low)>>1);
            /*if(data[middle] == k && (middle == 0 || data[middle-1] != k)){
                //开启找第一个k的判断
                return middle;
            }*/
            if(data[middle] == k && (middle == data.size()-1 || data[middle+1] != k)){
                //开启找最后一个k的判断
                return middle;
            }
            if(data[middle] > k)
                high = middle - 1;
            else
                low = middle + 1;
        }
        return -1;
    }

可以把两个函数写成一个,并且可以把判断条件合并判断,逐次改进

int GetNumberOfK(vector<int> data ,int k) {
        //采用二分查找
        if(data.size() == 0)
            return 0;
        int left = GetCore(data,0,data.size()-1,k,true);
        if(left == -1)return 0;
        int right = GetCore(data,left,data.size()-1,k,false);
        return right-left+1;
    }
     int GetCore(vector<int>& data,int low,int high,int k,bool less){
        int middle;
        while(low <= high){
            middle = low + ((high - low)>>1);
            if(less && data[middle] == k && (middle == 0 || data[middle-1] != k)){
                //开启找第一个k的判断
                return middle;
            }
            if(!less && data[middle] == k && (middle == data.size()-1 || data[middle+1] != k)){
                //开启找最后一个k的判断
                return middle;
            }
            if(data[middle] > k)
                high = middle - 1;
            else if(data[middle] == k && less)
                high = middle - 1;
            else
                low = middle + 1; 
                /*
            if(less){
                //如果当前是判断最小的
                if(data[middle] >= k)
                    high = middle - 1;
                else
                    low = middle + 1;
            }else{
                //如果当前是判断最大的
                if(data[middle] > k)
                    high = middle - 1;
                else
                    low = middle + 1;
            }*/
        }
        return -1;
    }

0~n-1中缺失的数字:一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/que-shi-de-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

整个数组都是递增有序的,并且缺失了一个数,我们可以计算出这n个数的和为n(n-1)/2,然后再计算一次数组的和,然后差值就是缺失的数,但是这样的复杂度是O(n)。
因为这个数组是递增有序的,应该要想到二分查找,那数组有什么特点呢,缺失了一个数的话,那么缺失数之前的数与下标应该是一样的,缺失后的数与下标应该是相差1的,因此我们应该可以修改一下二分查找使其找出第一个与下标不一致的数,下标就是缺失的数,那么如何判断呢,就是要么找到这个数下标是0不然它的前一个数应该是与下标一样的。

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        //二分查找,找出第一个下标和数不同的数
        if(nums.size() == 0)return 0;
        int low = 0,high = nums.size()-1;
        int middle;
        while(low <= high){
            middle = low + ((high - low) >> 1);
            if(nums[middle] != middle && (middle == 0 || nums[middle - 1] == middle - 1))
                return middle;
            else if(nums[middle] == middle)
                low = middle+1;
            else
                high = middle-1;
        }
        return nums.size();
    }
};

数组中数值和下标相等的数字:假设一个单调递增的数组的每个元素都是整数并且是唯一的,请编写一个函数,找出数组中任意一个数值等于其下标的元素。例如[-3,-1,1,3,5]

可以采用顺序查找,但是其实递增的特性,因此要思考采用二分查找,找出其二分的规律,假设有一个数等于其下标,下一个数大于下标,那么大于下标的数之后的数必定都是大于下标的,如果有一个数小于下标,那么其左边的数必定也是小于下标的,因此可以依据下标与数之间的关系进行二分,并且如果要找出多个数必定是在相等的周围才有可能存在相等的数。

int getEqual(vector<int> data){
	if(data.size() == 0)
		return -1;
	int low = 0,high = data.size()-1;
	int middle;
	while(low <= high){
		middle = low +((high-low) >> 1);
		if(data[middle] == middle)
			return middle;
		else if(data[middle] > middle)
			high = middle - 1;
		else 
			 low = middle + 1;
	}
	return -1 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值