剑指 Offer第53题 - II. 0~n-1中缺失的数字

182 阅读2分钟

这是我参与8月更文挑战的第13天,活动详情查看: 8月更文挑战

题干

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

示例 1:

 输入: [0,1,3]
 输出: 2

示例 2:

 输入: [0,1,2,3,4,5,6,7,9]
 输出: 8

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

解法:

看到这里我想了想,直接无脑循环找不适合当前的值的数(就是当前的元素于当前下标不等时)直接跳出循环返回结果。

 var missingNumber = function (nums) {
      for (let i = 0; i <= nums.length; i++) {
          if(nums[i]!==i){
              return i
          }
      }
      return ''
 };

写完以后,看了一下,发现了一句神评:“所有题都拿来遍历,offer也就遍历到别人那里去了”,笑死我了,原来我没有利用有序数组这个条件,虽然上面的解法也算是用到了有序,但是我们听到有序时,首先应该想到的还应该是二分法呀。

怎么二分呢?

首先我们清楚我们的数组中缺失了一个元素,所以它一定是两个连续的数组,我们就是要找到两个连续数组的交界处。

左子节点:nums[i]=i

右子节点:nums[i]!=i

因此二分的条件也就比较明确了:

 middle[mid]==mid   说明目前是左子区间  mid=low+1
 middle[mid]!=mid   说明目前是右子区间  mid=max-1

当我们跳出循环时,i和j最终就会指向右子区间的头开头和左子区间的结尾,所以我们直接返回i就可以

代码实现:

 /**
  * @param {number[]} nums
  * @return {number}
  */
 var missingNumber = function (nums) {
     let low = 0;
     let max = nums.length-1;
     while (low <= max) {
         var middle = Math.floor((low + max) / 2)
         if (middle == nums[middle]) {
             low = middle + 1
         } else {
             max = middle - 1
         }
     }
     return low
 };

\