【题目】
给定一个包含从0、1、2,...,n中获取的n个不同数字的数组,找到该数组中缺少的一个。
Example 1:
Input: [3,0,1]
Output: 2
Example 2:
Input: [9,6,4,2,3,5,7,0,1]
Output: 8
Example 3:
Input: [0,1]
Output: 2
注意:您的算法应以线性运行时复杂度运行。 您能否仅使用恒定的额外空间复杂度来实现它?
【解法】
思路:一种情况是缺失值在中间(example1和2),还有一种是缺失值在边上,见example3,所以分开处理。
构建一个有序列表,与排序后的列表一一比对,比对不成功的就是缺失值所在的地方。
class Solution: def missingNumber(self, nums: List[int]) -> int: nums.sort() nlist = list(range(len(nums)+1)) if nums == nlist[0:-1]: return len(nums) for i in range(0,len(nums)): if nums[i] != nlist[i]: return nlist[i]
Runtime: 160 ms, faster than 30.48% of Python3 online submissions for Missing Number. Memory Usage: 15.1 MB, less than 39.86% of Python3 online submissions for Missing Number. 【解法二】 思路同上,另一种写法
class Solution: def missingNumber(self, nums): nums.sort() # Ensure that n is at the last index if nums[-1] != len(nums): return len(nums) # Ensure that 0 is at the first index elif nums[0] != 0: return 0 # If we get here, then the missing number is on the range (0, n) for i in range(1, len(nums)): expected_num = nums[i-1] + 1 if nums[i] != expected_num: return expected_num
-
Time complexity : O(nlgn)\mathcal{O}(nlgn)O(nlgn)
The only elements of the algorithm that have asymptotically nonconstant time complexity are the main
for
loop (which runs in O(n)\mathcal{O}(n)O(n) time), and thesort
invocation (which runs in O(nlgn)\mathcal{O}(nlgn)O(nlgn) time for Python and Java). Therefore, the runtime is dominated bysort
, and the entire runtime is O(nlgn)\mathcal{O}(nlgn)O(nlgn). -
Space complexity : O(1)\mathcal{O}(1)O(1) (or O(n)\mathcal{O}(n)O(n))
In the sample code, we sorted
nums
in place, allowing us to avoid allocating additional space. If modifyingnums
is forbidden, we can allocate an O(n)\mathcal{O}(n)O(n) size copy and sort that instead.
【解法三】hash set
思路:最直接的思路是直接检查我们期望的数字是否存在。最简单的方法是用线性查找,我们可以使用HashSet来获取恒定时间的包含查询和整体线性运行时。
class Solution: def missingNumber(self, nums): num_set = set(nums) n = len(nums) + 1 for number in range(n): if number not in num_set: return number
-
Time complexity : O(n)\mathcal{O}(n)O(n)
Because the set allows for O(1)\mathcal{O}(1)O(1) containment queries, the main loop runs in O(n)\mathcal{O}(n)O(n) time. Creating
num_set
costs O(n)\mathcal{O}(n)O(n) time, as each set insertion runs in amortized O(1)\mathcal{O}(1)O(1) time, so the overall runtime is O(n+n)=O(n)\mathcal{O}(n + n) = \mathcal{O}(n)O(n+n)=O(n). -
Space complexity : O(n)\mathcal{O}(n)O(n)
nums
contains n−1n-1n−1 distinct elements, so it costs O(n)\mathcal{O}(n)O(n) space to store a set containing all of them.
【解法四】3位操作
思路:利用XOR是它自己的逆,在线性时间中找到丢失的元素。
算法:因为我们知道nums包含n个数字,并且在范围上恰好缺少一个数字[0..n-1],我们知道n为单位的缺失数字。 因此,如果我们将整数初始化为n并将其与每个索引和值进行XOR,剩下的就是我们要找的缺失数字。 考虑以下示例(为方便直观,对值进行了排序,但不必如此):(没懂(((φ(◎ロ◎;)φ)))
XOR(二进制运算),一般指异或,英文exclusive OR,是一个数学运算符号。异或的数学符号为“⊕”,计算机符号为“xor”。其运算法则为:a⊕b = (¬a ∧ b) ∨ (a ∧¬b)如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
class Solution: def missingNumber(self, nums): missing = len(nums) for i, num in enumerate(nums): missing ^= i ^ num return missing
-
Time complexity : O(n)\mathcal{O}(n)O(n)
Assuming that XOR is a constant-time operation, this algorithm does constant work on nnn iterations, so the runtime is overall linear.
-
Space complexity : O(1)\mathcal{O}(1)O(1)
This algorithm allocates only constant additional space.
【解法五】 gauss formula
通过公式在线性时间内计算预期总和,以及现列表的总和,两个和的差值就是缺失值的大小。
class Solution: def missingNumber(self, nums): expected_sum = len(nums)*(len(nums)+1)//2 actual_sum = sum(nums) return expected_sum - actual_sum
-
Time complexity : O(n)\mathcal{O}(n)O(n)
Although Gauss' formula can be computed in O(1)\mathcal{O}(1)O(1) time, summing
nums
costs us O(n)\mathcal{O}(n)O(n) time, so the algorithm is overall linear. Because we have no information about which number is missing, an adversary could always design an input for which any algorithm that examines fewer than nnn numbers fails. Therefore, this solution is asymptotically optimal. -
Space complexity : O(1)\mathcal{O}(1)O(1)
This approach only pushes a few integers around, so it has constant memory usage.