# 資訊 :::info - Question: 41. First Missing Positive - From: Leetcode Daily Challenge 2024.03.26 - Difficulty: Hard ::: --- # 目錄 :::info [TOC] ::: --- # 題目 Given an unsorted integer array `nums`. Return the smallest positive integer that is not present in `nums`. You must implement an algorithm that runs in $O(n)$ time and uses $O(1)$ auxiliary space. > Example 1: :::success - Input: `nums = [1,2,0]` - Output: 3 - Explanation: The numbers in the range `[1,2]` are all in the array. ::: > Example 2: :::success - Input: `nums = [3,4,-1,1]` - Output: 2 - Explanation: 1 is in the array but 2 is missing. ::: > Example 3: :::success - Input: `nums = [7,8,9,11,12]` - Output: 1 - Explanation: The smallest positive integer 1 is missing. ::: > Constraints: :::success - 1 <= `nums.length` <= $10^5$ - $-2^{31}$ <= `nums[i`] <= $2^{31} - 1$ ::: --- # 解法 ## 概念 久違了,在最忙的幾天給我塞 hard,真有你的 leetcode! 這題感覺跟昨天很像,一樣是透過 mark 成負的來當作 flag 去做後續判斷 因為題目說要找 first missing positive,當題目給大小為 `n` 的 array 時,可以猜到解答肯定是 `[1:n+1]` 這段區間,而 `n+1` 會出現在當 array 剛好就是 `[1, 2, ..., n]` 的時候 所以在一開始我把整條 array traverse 過一次,把在我關心的元素 (aka `[1:n]`) 以外全部置換成 `n+1`,其實只是要換成一個不會在 `[1:n]` 之中,等等可以判斷的數字即可 接著重新 traverse 過這條 array,從第零個開始,我去取該位置的數值,這時候得到的結果應該就會是 [1:n+1],而 `n+1` 正好就是那些我不想關心的元素,可以直接忽略(第 12 - 13 行),再來第 14 行是要把該數值變成 0-index,最後就把對應 index 的數值改成負的(第 15 - 16 行),代表該 index + 1 是出現在 `nums` 過的,而為什麼第 11 行要用絕對值取值也是這個原因 最後第 18 - 21 行就是在找第一個不為負的 index 是誰,其加一就會是第一個沒出現在 `nums` 的正數 如果都沒有,代表 `nums = [1:n]`,那就是要回傳 `n+1`(第 23 行) ## 程式碼 ```python= class Solution: def firstMissingPositive(self, nums: List[int]) -> int: # Reform nums: each element in range [1:n+1] n = len(nums) for i in range(n): if nums[i] <= 0 or nums[i] > n: # Those element I do not care nums[i] = n + 1 # Traverse nums and mark all existing numbers for i in range(n): num = abs( nums[i] ) if num > n: # Those element I do not care continue num -= 1 # To fit the 0-index if nums[num] > 0: # Those element I do care ([1:n]) nums[num] = -1 * nums[num] # Mark negative as the (index + 1) "in" nums # Find the first missing positive for i in range(n): if nums[i] > 0: # Positive means that (index + 1) is not in nums return i+1 return n+1 # [1:n] are all in nums, the first missing positive is n+1 ``` --- # 複雜度 ## 時間複雜度 首先排除我不關心的 element 花了一次 $O(n)$,traverse 所有 element 並 mark 成負的那時候又花了一次 $O(n)$,最後尋找 first missing positive 也花了一次 $O(n)$,整體是 $O(3n) = O(n)$ 題目的 hint 說「記得 $O(2n) = O(n)$」,說不定其他人比較快是因為這樣? ![TimeComplexity20240326](https://hackmd.io/_uploads/S1YrSsJyC.png =80%x) ## 空間複雜度 大多數的空間需求都在 `nums` 裡面處理完,所以跟題目要求一樣是 $O(1)$ ![SpaceComplexity20240326](https://hackmd.io/_uploads/B1CISok10.png =80%x)