概述
转载本文章请标明作者和出处
本文出自《Darwin的程序空间》
本文题目和部分解题思路来源自《剑指offer》第二版
题目
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字
示例:
输入: [0,1,3]
输出: 2
解题分析
首先这道题能想到的是,0-n-1,之内的所有数字,只有一个数字不在这个数组里面,那么我们的的做法就很简单了,我们可以先求出0-n-1的和是多少,数组里面不就是少一个数字么,我们用0-n-1的和减去数组里面的所有数字,得出来的就是缺少的那个数字,这种做法的时间复杂度为O(n);
但是,题目中给我们的是一个递增的数组,显然不仅仅是想让我们用这种方法来实现;我们可以使用二分法来处理这个问题;
我们来用计算机思维确认一下我们需要找的是什么数,缺失的那个数字,其实就是比它索引位置上要大1的数字,但是这样还不行,因为从那个确实数字之后的所有数字都比它的索引值要大,还必须得是第一个比它索引位置上要大1的数字的索引值就是我们要找的那个缺失的数字;
首先,为什么增强我们代码的健壮性,有一些特殊情况可以处理,比如,如果这个数组没有数字是空的,那么我们可以理解为这是一个长度为1的只有0的数组,缺失了元素0,于是返回0即可,如果长度是1,只有两种情况,0或1,是1的话缺少0,是0的话缺少1,我们直接1减去数组里面唯一的值返回即可,如果这个数组的最后一个元素还是等于它的索引值呢?说明他缺少最后一个元素,也就是数组的长度值,举例【0,1】就是【0,1,2】缺少【2】,【2】也恰好是【0,1】的长度;
剩下的事情,我们就可以直接进行二分查找,如果中间元素等于它的索引值,就说明目标值还在右边,我们让左指针加一,如果中间元素大于索引值,那就要看看中间元素前一个的元素是不是等于它的索引值(还有一种情况是前面没有元素,例如【1,2,3】,其实我们也找到了),如果是的话就返回结果(中间元素的索引值),如果没有,那就是答案还在左边,我们让右指针等于中间指针减一;理论上不存在中间元素小于索引值;
代码(JAVA实现)
ps:这里笔者使用的jdk为1.8版本
- 求和相减法
public int missingNumber(int[] nums) {
int sum = nums.length * (nums.length + 1) / 2;
for (int num : nums) {
sum -= num;
}
return sum;
}
- 二分法
class Solution {
public int missingNumber(int[] nums) {
if (Objects.isNull(nums) || nums.length == 0) {
return 0;
} else if (nums.length == 1) {
return 1 - nums[0];
} else if (nums[nums.length - 1] == nums.length - 1) {
return nums.length;
}
int left = 0;
int right = nums.length - 1;
while (left <= right) {
// 这里是左节点加右节点的和除以2
int mid = left + ((right- left) >> 1);
int num = nums[mid];
if (num == mid) {
left = mid + 1;
} else if (num > mid && (mid - 1 < 0 || nums[mid - 1] == mid - 1)) {
return mid;
} else if (num > mid) {
right = mid - 1;
}
}
// 这种情况就是出现问题了
return -1;
}
}
最后
以上就是感性手链为你收集整理的剑指offer | 面试题53 - II. 0~n-1中缺失的数字的全部内容,希望文章能够帮你解决剑指offer | 面试题53 - II. 0~n-1中缺失的数字所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复