[Leetcode解題] 41. First Missing Positive

5 April 2024
hard HashTable

題目:

41. First Missing Positive 給定一個未排序的整數陣列 nums。返回未出現在 nums 中的最小正整數。

你必須實現一個時間複雜度為 $O(n)$,額外空間複雜度為 $O(1)$ 的算法。

解題思路:

我們可以利用陣列本身的索引和值的關係來解決這個問題。我們將 nums 當作一個hash表,將每個正整數放到其對應的索引位置上。接著遍歷這個hash表,找出第一個未出現的正整數即可。

Example 1:

Input: nums = [1,4,5,2] 經過一些交換,nums會變成[1,2,5,4] Output: 3

  • 把正整數放到對應的索引位置上,陣列狀態為 [1, 2, 5, 4]。
  • 檢查缺失的數字
    • 索引 0 的位置應該是 1,因此正確。
    • 索引 1 的位置應該是 2,因此正確。
    • 索引 2 的位置應該是 3,但是是 5,表示 3 是第一個未出現在陣列中的正整數。

Python 實作:

class Solution:
    def firstMissingPositive(self, nums: List[int]) -> int:
        n = len(nums)
        for i in range(n):
            while 1 <= nums[i] <= n and nums[nums[i] - 1] != nums[i]:
                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

C++ 實作:

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        const int n = nums.size();
        for (int i = 0; i < n; ++i) {
            while (nums[i] > 0 && nums[i] <= n && nums[nums[i] - 1] != nums[i]) {
                swap(nums[nums[i] - 1], nums[i]);
            }
        }
        for (int i = 0; i < n; ++i) {
            if (nums[i] != i + 1) {
                return i + 1;
            }
        }
        return n + 1;
    }
};

複雜度分析:

  • 時間複雜度:
    • 遍歷一次陣列(交換元素): 每個元素最多只會被交換一次,並且被交換到正確的位置,因此每個元素只會被訪問常數次。因此把正整數放到對應的索引位置上需要 $O(n)$ 的時間,其中 $n$ 為陣列的長度。
    • 第二次遍歷(找出第一個未出現的正整數): 這也需要花費 $O(n)$ 的時間。
  • 空間複雜度: 我們只使用了常數額外空間,因此空間複雜度為 $O(1)$。