剑指 Offer 53 - II. 0~n-1中缺失的数字
https://leetcode-cn.com/problems/que-shi-de-shu-zi-lcof/
数学法
递增的等差数列之和为n*(n-1)/2,n是元素个数,数组之和可以求到,它们的差就是要找的数字
class Solution {
/**
* @param Integer[] $nums
* @return Integer
*/
function missingNumber($nums) {
//count($nums)比真实元素个数少1
return count($nums)*(count($nums)+1)/2 - array_sum($nums);
}
}
但很显然这并不是最优解,不说复杂度问题,单凭它需要算全部的数值之和很可能导致内存溢出就说明它是不安全的(虽然本题指定的范围不会导致溢出,但仍然不推荐这样写)。
顺序查找
如果不跳,每个下标与其数值正好是对应的...
function missingNumber($nums) {
if($nums==[0]){
return 1;
}
for($i=0;$i<count($nums);$i++){
if($nums[$i] != $i){
return $i;
}
}
return $i;
}
与其类似的还有两个相邻元素之和、之差求法
但这些都是线性遍历数组,在排序数组中找一个数字,二分查找也可。
时间O(n),空间O(1)
二分查找
如何确定缺省值在左边还是右边?从之前观察到的规律可以知道,如果没有缺省,$nums[$i]==$i应该成立,一旦$nums[$i]<$i,说明出现了缺省
class Solution {
/**
* @param Integer[] $nums
* @return Integer
*/
function missingNumber($nums,$left=0,$right=-1) {
if($right==-1){
$right = count($nums)-1;
}
while($left < $right){
$mid = intval(($left+$right)/2);
if($nums[$mid] == $mid){
return $this->missingNumber($nums,$mid+1,$right);
}else{
return $this->missingNumber($nums,$left,$right-1);
}
}
return $nums[$right]==$right ? $right+1 : $right;
}
}
二分查找的时间复杂度,最优情况下是每次真的能在最中间分开,那么每次要找的数组范围就是n、n/2、n/4...,,x=log(
) ,即O(log(
)) .本例中几乎是等差数列,恰好就是二分查找的最优情况。
二分查找在最差情况下退化为普通的遍历,O(n),本例不会出现此情况。
O(log(n)),但是空间复杂度需要n+n/2+n/4...=2/3n,O(n)级别,与前面顺序查找的O(1)相比是非常典型的空间换时间方式。