剑指offer 53 数字在排序数组中出现的次数

题目描述

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

思路一:
利用二分法找到等于k的位置,但可能左右两边都有k,所以需要在左右两边顺序扫描,分别找出第一个k和最后一个k。

因为要查找的数字在长度为n的数组中可能出现n次,所以时间复杂度是O(n)

代码:

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        if(data.size()==0)
            return 0;
        int low=0;
        int high=data.size()-1;
        while(low<=high)
        {
         int mid=(low+high)/2;
          if(k>data[mid])
              low=mid+1;
          else if(k<data[mid])
              high=mid-1;
          else
          {
              int i,j;
           for(i=mid;i>=0;i--)
               if(data[i]!=k)
                   break;
            for(j=mid+1;j<=data.size();j++)
               if(data[j]!=k)
                   break;
            return j-i-1;
          }
        }
        return 0;
    }
};
思路二:
仍然使用二分查找思想,尝试不使用两边扫描,便能找到第一个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)
                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>=0&&data[mid+1]!=k)
                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},我们发现,元素值与其下标的差是递增且过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;

}




猜你喜欢

转载自blog.csdn.net/weixin_41413441/article/details/80670821