數組特性的妙用!如何找到「缺失的第一個正數」

  • 2019 年 10 月 6 日
  • 筆記

作者 | P.yh

今天分享的題目來源於 LeetCode 第 41 號問題:缺失的第一個正數。題目難度為 Hard。本文使用了一個比較 Trick 的解法。

題目描述

給定一個未排序的整數數組,找出其中沒有出現的最小的正整數。

示例 1:

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

示例 2:

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

示例 3:

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

說明:

你的演算法的時間複雜度應為O(n),並且只能使用常數級別的空間。

題目解析

給一個整形數組,找出最小缺失的正整數,例如 [0,-1,2] 中最小缺失的正整數就是 1,[ 1,2 ,4 ,9 ] 中最小缺失的正整數就是 3。

這道題如果不加上 O(n) 時間和 O(1) 空間這樣的限定條件,應該再簡單不過,但是加上了這兩個要求,一下子使問題變得棘手。

怎麼思考呢?

首先這道題給定的條件很有限,輸入參數就 只有數組 ,如果非要用 O(n) 時間和 O(1) 空間來做的話,表示我們除了輸入數組以外,不能藉助任何其他的數據結構。

數組應該是屬於一類最最基礎的數據結構,除去 length 之外,就只有兩個屬性 index 和 value,那這道題就變成了 如何利用數組的 value 和 index 之間的關係來找到最小缺失正整數 ,如果想到了這一點,就已經成功了一半。

如果繼續想下去有幾點是可以明確的:

  1. 缺失的正整數肯定在 [1, array.length + 1] 這個範圍內
  2. 我們可以交換輸入數組中的元素的位置來讓 index 和 value 的關係更加明確
  3. 保證 index 和 value 的關係後,我們可以通過 index 來判定整數的存在性

第一點很好理解,一個數組總共有 array.length 這麼多個數,全部排滿,也就是 1,2,…array.length, 那麼答案就是 array.length + 1,沒有排滿,那麼在這之間肯定是有缺失元素的。

第二點是說我們可以通過交換來讓 index 和 value 形成對應,我們看的是 value,但是 index 可以輔助我們尋找。

前兩點明確了,第三點就是從頭到尾尋找答案的過程。

程式碼實現

public int firstMissingPositive(int[] nums) {      if (nums == null || nums.length == 0) {          return 1;      }        for (int i = 0; i < nums.length;) {          if (nums[i] <= 0 || nums[i] > nums.length || nums[nums[i] - 1] == nums[i]) {              i++;              continue;          }            // swap          int tmp = nums[nums[i] - 1];          nums[nums[i] - 1] = nums[i];          nums[i] = tmp;      }        for (int i = 0; i < nums.length; ++i) {          if (nums[i] != i + 1) {              return i + 1;          }      }        return nums.length + 1;  }  

總結

程式碼中 index 和 value 的對應關係是 index = value - 1,程式碼實現有兩點需要注意。

  • 第一點,交換完後,需要判斷交換過來的數是否需要被放到相應的地方,例如 [2,3,1]
  • 第二點,元素越界的話,以及元素 value 已經和 index 對應上了,那麼就應該繼續遍歷,例如 [0,-1,1] 和 [1,1]。

總的來說這道題並沒有涉及什麼演算法和數據結構的應用,有點像腦筋急轉彎的感覺,想到了就做的出,想不到的話就做不出,但是它給我們解數組問題提供了一個新的方向:利用 index 和 value 的對應關係來輔助求解。

Tags: