[LeetCode解題攻略] 41. First Missing Positive

更新於 發佈於 閱讀時間約 5 分鐘

題目描述

給定一個未排序的整數數組 nums,找出其中的最小的缺失的正整數

  • 必須設計一個時間複雜度為 O(n) 的解法,並且空間複雜度為 O(1)

範例 1

輸入: nums = [1,2,0]
輸出: 3

範例 2

輸入: nums = [3,4,-1,1]
輸出: 2

範例 3

輸入: nums = [7,8,9,11,12]
輸出: 1

解題思路

  1. 我們需要找到數組中最小的缺失正整數
  2. 題目要求時間複雜度為 O(n),這意味著傳統的排序方法(O(n log n))不適用。
  3. 同時,要求只使用常數空間,這限制了我們不能使用額外的數組來儲存結果。

基於以上限制,解法核心是將數組作為哈希表來操作,透過將元素放在正確的位置來確定缺失的數字。


解法一:原地雜湊(Cyclic Sort)

核心思想

將每個數字放到對應的索引位置,例如:

  • 如果數字為 x,且 1 <= x <= nn 是數組長度),我們應該將 x 放在索引 x-1 的位置。

最後,掃描數組,第一個數字不符合其索引的,就是缺失的正整數。


步驟

  1. 遍歷數組,將每個數字放到正確的位置:
    • 如果 nums[i] 的值在 [1, n] 範圍內,且 nums[i] != nums[nums[i] - 1],則交換 nums[i] 與 nums[nums[i] - 1]。
  2. 再次遍歷數組,找到第一個 nums[i] != i + 1 的位置,返回 i + 1
  3. 如果數組中所有數字都在正確位置,則返回 n + 1

程式碼

class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
n = len(nums)

# 將每個數字放到正確的位置
for i in range(n):
while 1 <= nums[i] <= n and nums[i] != nums[nums[i] - 1]:
nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]

# 找出第一個缺失的正整數
for i in range(n):
if nums[i] != i + 1:
return i + 1

return n + 1

時間與空間複雜度分析

  • 時間複雜度:O(n)
    • 每個數字最多只會被移動一次,因此整體時間為線性。
  • 空間複雜度:O(1)
    • 我們在原地操作數組,未使用額外的儲存空間。

解法二:標記法

核心思想

  1. 利用數組本身作為狀態標記
    • 將數組中的每個數字(如果在範圍內 1 <= x <= n)標記到對應的索引位置。
    • 我們通過將數字對應位置的值設為負數來標記它已經出現過。
  2. 掃描標記結果
    • 如果某個位置的值仍為正,說明該索引的數字缺失。

步驟

  1. 遍歷數組,將 1 <= nums[i] <= n 的數字標記到對應索引。
  2. 再次遍歷數組,找到第一個值為正的索引,返回其對應數字 i + 1
  3. 如果所有位置都已標記,則返回 n + 1

程式碼

class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
n = len(nums)

# 將不在範圍內的數字設為 n + 1
for i in range(n):
if nums[i] <= 0 or nums[i] > n:
nums[i] = n + 1

# 標記出現的數字
for i in range(n):
num = abs(nums[i])
if num <= n:
nums[num - 1] = -abs(nums[num - 1])

# 找出第一個缺失的正整數
for i in range(n):
if nums[i] > 0:
return i + 1

return n + 1

時間與空間複雜度分析

  • 時間複雜度:O(n)
    • 需要兩次遍歷數組。
  • 空間複雜度:O(1)
    • 使用數組本身作為標記,未使用額外的儲存空間。

結論

  1. 原地哈希法 是解決該問題的經典解法,特別適合實現簡單的場景。
  2. 標記法 更適合處理帶有範圍約束的問題,尤其是當需要快速排除無效數字時。

兩種解法都滿足題目對時間和空間的要求,可以根據需求選擇適合的實現方式!

留言
avatar-img
留言分享你的想法!
avatar-img
追極光的北極熊|軟體工程師的小天地
7會員
139內容數
歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
2025/04/04
給定一個非負整數陣列 nums,其中 nums[i] 代表你在索引 i 處最多可以向右跳幾步。 請判斷是否能夠從索引 0 跳到最後一個索引。
2025/04/04
給定一個非負整數陣列 nums,其中 nums[i] 代表你在索引 i 處最多可以向右跳幾步。 請判斷是否能夠從索引 0 跳到最後一個索引。
2025/03/28
給定一個 m x n 的矩陣 matrix,請按照 螺旋順序(spiral order) 返回矩陣中的所有元素。
2025/03/28
給定一個 m x n 的矩陣 matrix,請按照 螺旋順序(spiral order) 返回矩陣中的所有元素。
2025/03/20
這道題是 LeetCode 的經典題之一,要求我們找出 一個子陣列,使其和最大,並返回這個最大和的數值。
2025/03/20
這道題是 LeetCode 的經典題之一,要求我們找出 一個子陣列,使其和最大,並返回這個最大和的數值。
看更多
你可能也想看
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
題目敘述 Patching Array 題目給定一個整數陣列, 請問還要補上多少個數字,才能用這些數字的和拼湊出所有1~n的整數。
Thumbnail
題目敘述 Patching Array 題目給定一個整數陣列, 請問還要補上多少個數字,才能用這些數字的和拼湊出所有1~n的整數。
Thumbnail
題目敘述 Single Number II 給定一個輸入陣列,已知有一個烙單的數字,其他剩餘的數字都恰巧出現三次。 請找出這個烙單的數字。 題目額外提出限制,請使用O(n)線性時間、O(1)常數空間複雜度的演算法。 測試範例 Example 1: Input: nums = [2,2,
Thumbnail
題目敘述 Single Number II 給定一個輸入陣列,已知有一個烙單的數字,其他剩餘的數字都恰巧出現三次。 請找出這個烙單的數字。 題目額外提出限制,請使用O(n)線性時間、O(1)常數空間複雜度的演算法。 測試範例 Example 1: Input: nums = [2,2,
Thumbnail
題目敘述 Single Number III 給定一個輸入陣列,已知有兩個烙單的數字,其他剩餘的數字都恰巧出現兩次。 請找出這兩個烙單的數字。 題目額外提出限制,請使用O(n)線性時間、O(1)常數空間複雜度的演算法。 測試範例 Example 1: Input: nums = [1,
Thumbnail
題目敘述 Single Number III 給定一個輸入陣列,已知有兩個烙單的數字,其他剩餘的數字都恰巧出現兩次。 請找出這兩個烙單的數字。 題目額外提出限制,請使用O(n)線性時間、O(1)常數空間複雜度的演算法。 測試範例 Example 1: Input: nums = [1,
Thumbnail
給定一個輸入非負整樹陣列nums,請找出k值,使得陣列中恰好有k個元素大於等於 k。如果無解,回傳-1。尋找k值的方法包括排序法和二分搜尋法,時間複雜度都為O(n log n),空間複雜度為O(1)。關鍵知識點是當解空間具有遞增或遞減的性質時,可以用二分搜尋法加快搜尋效率。
Thumbnail
給定一個輸入非負整樹陣列nums,請找出k值,使得陣列中恰好有k個元素大於等於 k。如果無解,回傳-1。尋找k值的方法包括排序法和二分搜尋法,時間複雜度都為O(n log n),空間複雜度為O(1)。關鍵知識點是當解空間具有遞增或遞減的性質時,可以用二分搜尋法加快搜尋效率。
Thumbnail
輸入給定一個已經從小到大排序好,而且彼此互質的整數陣列, 請問任取兩數分別當作分子、分母,第k小的分數是多少? 輸出請以 [分子,分母] 的形式回傳答案。
Thumbnail
輸入給定一個已經從小到大排序好,而且彼此互質的整數陣列, 請問任取兩數分別當作分子、分母,第k小的分數是多少? 輸出請以 [分子,分母] 的形式回傳答案。
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目敘述 題目會給定我們一個整數陣列nums,要求我們把裡面的0做元素交換,把0都搬到陣列的右邊。題目要求必須in-place在原本的陣列裡面做操作,不可以額外建立新的陣列。 題目的原文敘述 測試範例 Example 1: Input: nums = [0,1,0,3,12] Outpu
Thumbnail
題目敘述 題目會給定我們一個整數陣列nums,要求我們把裡面的0做元素交換,把0都搬到陣列的右邊。題目要求必須in-place在原本的陣列裡面做操作,不可以額外建立新的陣列。 題目的原文敘述 測試範例 Example 1: Input: nums = [0,1,0,3,12] Outpu
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News