[二分] 剑指 Offer 53 - II. 0~n-1中缺失的数字

134 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情

每日刷题 2022.08.11

题目

  • 一个长度为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

提示

  • 1 <= 数组长度 <= 10000

解题思路

  • 对于本题而言,可以直接模拟,也可以使用二分来进行查找。
  • 由于题目中提到了这是一个递增的排序数组,并且每个数字都在范围0~n-1之内。那么对于缺失的数据之前,一定满足nums[i] === i,而对于缺失的数据之后一定不满足nums[i] ==== i。因此可以使用二分,找到不满足的下标,输出即可。
  • 类似的题目剑指 Offer 11. 旋转数组的最小数字,也是使用二分的解法,但是这里的二段性就比本题的要较为难理解一些。

二分

  • 二分的本质是:二段性
  • 根据题意可知,数据和数组下标是对应的,如果中间有缺失,则数据肯定比下标大,而且又是有序数组,利用二分查找,条件为nums[mid]>mid
  • 遍历,当前的数 + 1不等于下一个索引的数,则返回当前的数 + 1
  • 特殊边界:第一个数不是0的时候就是缺失0,到最后一个数的时候还没有return上面的正常情况就是缺失最后一个数 + 1

AC代码

/**
 * @param {number[]} nums
 * @return {number}
 */
var missingNumber = function(nums) {
  // 首先:长度为n-1,一共有n个数字,也就是包含长度在内的数字
  // 有序的就需要二分,具有二段性,这个一定要想清楚。
  // 有序的,那么缺失的前面一段,就是nums[i] = i, 缺失的后面一段就不满足nums[i] = i
  let n = nums.length;
  let idx = binary();
  return idx;
  function binary() {
    let l = -1, r = n;
    while(l + 1 != r) {
      let mid = Math.floor((l + r) / 2);
      if(mid === nums[mid]) {
        l = mid;
      } else {
        r = mid;
      }
    }
    return r;
  }
};