0~n-1中缺失的数字--二分法

0x01.问题

一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
输入示例: [0,1,2,3,4,5,6,7,9]
输出示例:8

C++函数形式:     int missingNumber(vector<int>& nums) 

0x02.简要分析

这其实是个非常简单的问题,读一下题目,大意是(把n-1转换为n更好理解):

  • 在一个长度为n的递增数组中,包含了0-n里面的n个,找出不在里面的。

题目很清晰,就是找一个数,而且还是一个递增的数组,于是简简单单的思路就有了,这个数只有三种可能,在数组第一位,最后一位,中间,于是我们可以分类判断一下就可以了。

  • 判断第一位是不是0,不是,就肯定是少了0
  • 然后判断中间的数字是不是等于上一位加1,不等于就是这个数减1。
  • 如果循环完了还没找到,就是最后一个数不在了。

普通的思路很简单,这里我们使用更加巧妙地二分法。

我们发现,这个数组其实是可以分为两部分的,第一部分就是满足nums[i]=i的,这里面都是连续的,第二部分就是不满足的,第一个不满足的数减去1就是我们要找的那个数。

这是一个有序序列,我们可以使用二分法去搜索这个第一个不满足的数。

  • left控制左边满足nums[i]=i的部分,right控制右边不满足的部分。
  • 每次取中,若满足nums[mid]=mid,说明要找的数在右边,left=mid+1,不满足说明在左边,right=mid-1
  • 最后当left>right时,nums[left]就是第一个不满足的数,我们要求的答案也就是nums[left]-1,其实也就是left

0x03.解决代码–普通遍历 --O(N)

int missingNumber(vector<int>& nums) {
    if(nums[0]!=0) return 0;
    for(int i=1;i<nums.size();i++){
        if(nums[i]!=nums[i-1]+1) return nums[i]-1;
    }
    return nums.size();
}

0x04,解决代码–二分法 --O(logN)

int missingNumber(vector<int>& nums) {
    int left=0;
    int right=nums.size()-1;
    while(left<=right){
        int mid=(left+right)/2;
        if(nums[mid]==mid) left=mid+1;
        else right=mid-1;
    }
    return left;
}

ATFWUS --Writing By 2020–03–27

你可能感兴趣的:(算法,算法面试题集)