LC 0041 [H] First Missing Positive - ALawliet/algorithms GitHub Wiki
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
i, n = 0, len(nums)
while i < n:
j = nums[i] - 1
if nums[i] > 0 and nums[i] <= n and nums[i] != nums[j]:
nums[i], nums[j] = nums[j], nums[i]
else:
i += 1
for i in range(n):
if nums[i] != i + 1:
return i + 1
return len(nums) + 1
holy sht this nums[nums[i]%n]+=n is brilliant. It stores information about nums[i] and still keep the information of nums[nums[i]]. Thanks for sharing this trick.
l = [1, 1, 1, 2, 2]
size = len(l) # 5
for e in l:
# 1 % 5 = 1
# 2 % 5 = 2
l[e % size] += size
print("Hashed", l) # [1, 16, 11, 2, 2]
# Modified
unhashed = l.copy()
for i, e in enumerate(unhashed):
unhashed[i] = e % size
print("Unhashed", unhashed) # [1, 1, 1, 2, 2]
print("Frequency")
for i, e in enumerate(l):
i_count = e//size
print(f'{i}: {i_count}')
# 0: 0
# 1: 3
# 2: 2
# 3: 0
# 4: 0
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
"""
:type nums: List[int]
:rtype: int
Basic idea:
1. for any array whose length is l, the first missing positive must be in range [1,...,l+1],
so we only have to care about those elements in this range and remove the rest.
2. we can use the array index as the hash to restore the frequency of each number within
the range [1,...,l+1]
"""
nums.append(0) # edge case: 1 element e.g. [1]
n = len(nums)
for i in range(len(nums)): #delete those useless elements
if nums[i] < 0 or nums[i] >= n:
nums[i] = 0
for x in nums: #use the index as the hash to record the frequency of each number
nums[x % n] += n
for i in range(1,len(nums)):
if nums[i] // n == 0:
return i
return n
def firstMissingPositive(self, nums: List[int]) -> int:
"""
For nums with length n, the possible result is in the range of
[1 : n + 1], we want to know the smallest integer in the range
of [1 : n] that is not in nums, if [1 : n] are all in nums,
the result is n + 1
So those numbers not in [1 : n] are not useful and we can just
change them to be 0
Then we go through nums, if nums[i] is in the range of
[1 : n], we use index (nums[i] - 1) to record that we have
seen nums[i] by adding n + 1 to nums[nums[i] - 1]
Finally we just need to find the first index i for which
nums[i] is less than n + 1 (which means we never met number
i + 1 so we did not add n + 1 to nums[i])
"""
n = len(nums)
for i in range(n):
if nums[i] < 1 or nums[i] > n:
nums[i] = 0
for i in range(n):
if 1 <= nums[i] % (n + 1) <= n:
ind = nums[i] % (n + 1) - 1
nums[ind] += n + 1
for i in range(n):
if nums[i] <= n:
return i + 1
return n + 1