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

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

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

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否则它的前一个数应该是与下标同样的。
less

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]

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

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 ;
}