剑指 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)