给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。
找到所有在 [1, n] 范围之间没有出现在数组中的数字。
您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。
示例:
输入:
[4,3,2,7,8,2,3,1]
输出:
[5,6]
解法一:
class Solution(object):
def findDisappearedNumbers(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
maxN = len(nums)
if maxN == 0:
return []
disappearedNumbers = [1 for i in range(maxN)]
for num in nums:
disappearedNumbers[num-1] = 0
result = []
for i in range(maxN):
if disappearedNumbers[i] != 0:
result.append(i+1)
return result
判断数字是否出现可以让我们很自然的想到用哈希表来记录,哈希表的读写速度为O(1),但是需要额外的内存O(n)来保存哈希表。这道题中因为数字是1到n,所以可以用数组下标的方式来模拟哈希表,下标即键,为数字减1。一开始我们获取数组长度n,然后创建一个长度为n,所有值都为1的列表来模拟哈希。随后遍历原nums数组,当一个numbe出现时,将哈希表中的值标为0。最后我们只需要遍历这个创建的数组,当遍历元素为非0时,将下标加1(即真实的数字)插入到result列表中。
该方法时间复杂度为O(n),空间复杂度为O(1)
解法二:
class Solution(object):
def findDisappearedNumbers(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
maxN = len(nums)
if maxN == 0:
return []
disappearedNumbers = [i+1 for i in range(maxN)]
for num in nums:
disappearedNumbers[num-1] = 0
for i in range(maxN-1, -1, -1):
if disappearedNumbers[i] == 0:
disappearedNumbers.pop(i)
return disappearedNumbers
解法二为解法一的改进版,不需要再用额外的空间创建新数组,而是在原来的disappearedNumbers上操作。修改了该数组的生成条件,假设n为3,那么解法1生成的列表为[1,1,1],而解法二生成的列表为[1,2,3]。最后我们只需要把所有的0元素pop出去,就得到了题目要求的答案。注意到我们这里需要从后往前遍历,不然pop就会出现下标问题。
该方法空间复杂度为O(1),但是时间复杂度为O(n^2),因为删除数组元组会涉及到后序元素的前移,需要O(n)的额外时间
解法三:
class Solution(object):
def findDisappearedNumbers(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
# Iterate over each of the elements in the original array
for i in range(len(nums)):
# Treat the value as the new index
new_index = abs(nums[i]) - 1
# Check the magnitude of value at this new index
# If the magnitude is positive, make it negative
# thus indicating that the number nums[i] has
# appeared or has been visited.
if nums[new_index] > 0:
nums[new_index] *= -1
# Response array that would contain the missing numbers
result = []
# Iterate over the numbers from 1 to N and add all those
# that have positive magnitude in the array
for i in range(1, len(nums) + 1):
if nums[i - 1] > 0:
result.append(i)
return result
这个官方解法比较巧妙,还是利用数组的下标在原数组上进行操作,在遍历时,如数字3,则去检查index = 2 (3-1) 的元素是否为负,如果为非负就把它标。利用这种方式,可以用负数表示这个下标已经出现过,即下标对应的下标+1的数字已经出现过。最后返回所有元素为正的下标+1值就为未出现的数列。 |