leetcode 剑指 Offer 53

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

题目描述

一个长度为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内的,还是有序数组,所以如果没有缺失的话,每个元素应该刚好在等于它的下标,但是现在缺失了一个,说明从这个元素的下标开始,下标都不等于该下标对应的值了。

那如果采用遍历的方式,碰到的第一个下标与值不一致的下标即是缺失的数字

1 class Solution {
2     public int missingNumber(int[] nums) {
3         // 遍历数组,如果值和下标不相等,直接返回下标
4         int i;
5         for(i = 0; i < nums.length && nums[i] == i; i++);
6         return i;
7     }
8 }

leetcode运行时间为0ms - 100%, 空间为39.5MB - 45.05%

复杂度分析:

时间复杂度:最多就把整个数组遍历一遍,所以时间复杂度为O(n)

空间复杂度:O(1)

思路二:二分法

如果arr[mid] == mid, 说明mid在缺失的元素之前,left = mid + 1, 否则说明mid在缺失的元素之后或者就是缺失的元素,right = mid - 1, 跳出时,变量 left 和 right分别指向 “右子数组的首位元素” 和 “左子数组的末位元素” 。因此返回 left 即可。

 1 class Solution {
 2     public int missingNumber(int[] nums) {
 3         // 二分法
 4         int left = 0, right = nums.length - 1;
 5         int mid = 0;
 6         while(left <= right){
 7             mid = (right + left) / 2;
 8             if(mid == nums[mid]){
 9                 left = mid + 1;
10             }else{
11                 right = mid - 1;
12             }
13         }
14         // 跳出时left指向右子数组的首位元素,rihgt指向右子数组的第一个元素
15         // 所以返回left
16         return left;   
17     }
18 }

leetcode运行时间为0ms - 100%, 空间为39.5MB - 45.05%

复杂度分析:

时间复杂度:二分法属于折半查找,所以时间复杂度为O(logn)

空间复杂度:O(1)