剑指53:数组在排序数组中出现的次数——折半查找——拓展(2)(3)

折半查找专场———有序数组的查找———————————————————————————————

题目描述1

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

思路:通过折半查找找到k开始和结束的位置。O(logn)

class Solution {
public:
    int GetFirstK(vector<int> data,int k,int start,int end){
        //折半查找注意边界条件
        if(start>end)
            return -1;
        int mid = (end+start)/2;
        int midval = data[mid];
        if(midval == k){
            if(mid-1>=start&&data[mid-1]==k)  //左侧还有k
                end = mid-1;
            else
                return mid;
        }
        else if(midval > k)
            end = mid-1;
        else
            start = mid+1;
        return GetFirstK(data,k,start,end);
    }
    int GetLastK(vector<int> data,int k,int start,int end){
      if(start>end)
          return -1;
        int mid = (end+start)/2;
        int midval = data[mid];
        if(midval == k)
        {
            if(mid+1<=end&&data[mid+1]==k) //右侧还有k
                start = mid+1;
            else
                return mid;
        }
        else if(midval > k)
            end = mid-1;
        else
            start = mid+1;
        return GetLastK(data,k,start,end);
    }
    int GetNumberOfK(vector<int> data ,int k) {
        if(data.empty())
            return 0;
        int first = GetFirstK(data,k,0,data.size()-1); 
        int last = GetLastK(data,k,0,data.size()-1);
        int number = 0;
        if(first>-1&&last>-1)
            number = last-first+1;
        return number;
    }
};

方法2:

//因为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;
    }

};

题目2:0到n-1中缺失的数字

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

思路:转化成下标与内容是否一致的问题,从左到右第一个不一致的位置的下标就是缺失的数,如果n-1个位置都一致,那缺失的就是最后一个数。

#include <cstdio>
#include<iostream>
#define nullptr NULL
using namespace std;
int GetMissingNumber(const int* numbers, int length)
{
    //数的范围从0~n-1 按序选n-1个数放入n-1长的数组
    //其中某一个位置开始下标和位置上的数不一致,返回下标即缺失的数。 
    if(!numbers||length<=0)
        return -1;
    int start = 0;
    int end = length-1;
    //该循环保证在n-1个位置上判定是否位置上的数与下标是否一致
    //缺失的数 以下标形式返回 
    //没有判定当这n-1个位置上下标全一致 即缺失数N-1
    while(start<=end)
    {
        int mid =(start+end)>>1;
        if(numbers[mid]!=mid)
        {
            if(mid-1>=start&&numbers[mid-1]!=mid-1)
                end = mid-1;
            else
                return mid; //mid=0或mid-1>=start时mid-1=numbers[mid-1];
        }

        else
            start = mid+1;
    }
    //判定前n-1个数均没有缺失,缺失的是n-1这个数
    if(start==length)
        return length;
    return -1;
} 

题目3

// 面试题53(三):数组中数值和下标相等的元素
// 题目:假设一个单调递增的数组里的每个元素都是整数并且是唯一的。请编程实
// 现一个函数找出数组中任意一个数值等于其下标的元素。例如,在数组{-3, -1,
// 1, 3, 5}中,数字3和它的下标相等。

#include <cstdio>
#define nullptr NULL

int GetNumberSameAsIndex(const int* numbers, int length)
{
    if(!numbers||length<=0)
        return -1; 
    int start = 0;
    int end = length-1;
    while(start<=end){
        int mid =(end+start)>>1;
        if(numbers[mid]==mid)                                                                                                                                                                                          
            return mid;
        else if(numbers[mid]>mid)
            end = mid-1;
        else
            start = mid+1;
    }   
    return -1; 
}



猜你喜欢

转载自blog.csdn.net/yanbao4070/article/details/80235348