题目
给定一个数组,包含从 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