面试题 17.19. 消失的两个数字

题目

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

以任意顺序返回这两个数字均可。

示例1:

输入: [1]
输出: [2,3]

示例2:

输入: [2,3]
输出: [1,4]

分析: 本题要求空间复杂度是 O ( 1 ) O(1) O(1), 有以下三种方法:
方法1: 假设缺失的两个数是a, b, 那么对N个数求和减去数组中的元素,就能得到 a + b a+b a+b的结果,同理对N个数求平方和减去数组中元素的平方和,就能得到 a 2 + b 2 a^2+b^2 a2+b2的结果,满足两个等式的a, b唯一

class Solution:
    def missingTwo(self, nums: List[int]) -> List[int]:
        N = len(nums) + 2
        n_sum = N*(N+1)//2
        nums_sum = sum(nums)
        sum_sub = n_sum - nums_sum
        n_squre = N*(N+1)*(2*N+1)/6
        nums_squre = 0
        for num in nums:
            nums_squre += num **2
        squre_sub = n_squre - nums_squre
        for num in range(1, sum_sub):
            if num**2 + (sum_sub - num)**2 == squre_sub:
                return [num, sum_sub - num]
        return []

方法2: 按照方法1求出两数之和, a + b = s a+b=s a+b=s, 假设a<b, 则必然满足a<s/2, b>s/2, 也就是说a在[1, s/2]区间, b在[s/2, s]区间,那么问题就演变成了找[1, s/2]中缺失的一个数问题,对1到s/2所有整数数求和,减去数组中小于s/2的数,就能得到其中缺失的一个数,那么自然就能得到另外一个数

class Solution:
    def missingTwo(self, nums: List[int]) -> List[int]:
        N = len(nums) + 2
        n_sum = N*(N+1)//2
        nums_sum = sum(nums)
        #缺失的两数之和等于sum_sub
        sum_sub = n_sum - nums_sum
        #因为缺了两个数,因此必然一个数小于sum_sub/2, 一个数大于sum_sub/2
        mid = sum_sub // 2
        half_sum = mid*(mid+1)//2
        left_sum = 0
        for num in nums:
            if num <= mid:
                left_sum += num
        small_num = half_sum - left_sum
        big_num = sum_sub - small_num
        return [small_num, big_num]

方法3: 对数组中添加两个数作为标志符,加入数组中不缺失数,那么理论上每一个位置都能对应其中一位数,比如数组第1位对应的数为2(数组下标从0开始),第2位对应数为3, 那么只需要对数组进行归位排序,最后遍历找到标志符对应的下标即可,由于我们知道每一个数在数组中所处的位置,只需要按位置进行归位,即可完成排序的过程

class Solution:
    def missingTwo(self, nums: List[int]) -> List[int]:
        nums += [-1, -1]
        print(nums)
        miss_num = []
        n = len(nums)
        for i in range(n):
            while nums[i] != i+1 and nums[i] != -1:
                nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]
        for i in range(n):
            if nums[i] == -1:
                miss_num.append(i+1)
        return miss_num
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值