268. Missing Number 丢失的数字

https://leetcode-cn.com/problems/missing-number/

Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missing from the array. For example, Given nums = [0, 1, 3] return 2

Follow up: Could you implement a solution using only O(1) extra space complexity and O(n) runtime complexity?

这道题给我们n个数字,是0到n之间的数但是有一个数字去掉了,让我们寻找这个数字,要求时间复杂度O(n)和空间复杂度O(1)。

解法1:

那么最直观的一个方法是用等差数列的求和公式求出0到n之间所有的数字之和,然后再遍历数组算出给定数字的累积和,然后做减法,差值就是丢失的那个数字,参见代码如下:

但是这种解法存在空间溢出的问题

class Solution:
    def missingNumber(self, nums: List[int]) -> int:
        sum = 0
        for i in nums:
          sum = sum+i
        length = len(nums)
        mis = (0+length)*(length+1)/2-sum
        return int(mis)

解法2:

使用位操作Bit Manipulation来解的,用到了异或操作的特性,^代表异或。异或虽然是二进制计算,但从大的理解上可以理解为如果数字n^n=0; n^m为一串二进制,其中有一位为1;0^n = n。所以假设array为[1,2,3],消失的数字为4,那么让整串数字[1,2,3,4]与[1,2,3]这七个数字进行异或操作,相同的抵消为0,那么只剩0^4 = 4,消失的数字为4。

class Solution:
    def missingNumber(self, nums: List[int]) -> int:
        res = 0
        for i in range(len(nums)):
            res ^= i^nums[i]
        res ^= len(nums)
        return res

解法3:

使用binary search O(logn)

index 0,1,2,3,4

nums0,2,3,4

如果mid==nums[mid], 那么left = left+1;如果mid<nums[mid],那么right = mid。最后left==right跳出循环,判断是否缺少最大值的可能性。

class Solution:
    def missingNumber(self, nums: List[int]) -> int:
        left, right = 0, len(nums)-1
        nums.sort()
        while(left<right):
            mid = (left+right)//2
            if mid== nums[mid]:
                left = mid+1
            elif mid<nums[mid]:
                right = mid
        if right == nums[right]:
            return right +1
        return right

类似的有消失两次的数字,原题https://leetcode-cn.com/problems/missing-two-lcci/

给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗?以任意顺序返回这两个数字均可。

与上一个问题相同,得到的res就是消失的两个数字n,m的异或,res的二进制一定有一个1,

可以采用两种方式求div为1的位置。

class Solution:
    def missingTwo(self, nums: List[int]) -> List[int]:
        res = 0
        for i in range(len(nums)):
            res ^= (i+1)^nums[i]
        res ^= (len(nums)+1)^(len(nums)+2)
        #求res的右边第一个1
        方法1:
        div = 1
        while (div&res == 0):
            div<<=1
        方法2:
        # div = res&-res
        #开始将list分成两类
        a, b = 0,0
        for ele in nums:
            if div&ele:
                a ^= ele
            else:
                b ^= ele
        for i in range(1, len(nums)+3):
            if div&i:
                a ^= i
            else:
                b ^= i
        return a,b

 

相似题目:

剑指 Offer 56 - I. 数组中数字出现的次数, https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/

137. 只出现一次的数字 II,  https://leetcode-cn.com/problems/single-number-ii/

136. 只出现一次的数字,   https://leetcode-cn.com/problems/single-number/

260. 只出现一次的数字 IIIhttps://leetcode-cn.com/problems/single-number-iii/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值