首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

LeetCode 334. Increasing Triplet Subsequence 解題報告:O(n) 時間 O(1) 空間貪心單調棧思路

     編輯:Java 綜合教學

LeetCode 334. Increasing Triplet Subsequence — 線性時間常數空間判斷遞增三元組

題目:給定未排序數組,判斷是否存在長度為 3 的遞增子序列 (索引 `i < j < k` 且 `nums[i] < nums[j] < nums[k]`)。要求 **O(n) 時間、O(1) 空間**。

示例:`[1,2,3,4,5]` → `true`;`[5,4,3,2,1]` → `false`。

錯誤直覺:三層循環 O(n³) (原始碼)

// 典型暴力:三層循環檢查所有三元組
for (int i = n-1; i >= 2; i--)
  for (int j = i-1; j >= 1; j--)
    if (nums[i] > nums[j])
      for (int k = j-1; k >= 0; k--)
        if (nums[j] > nums[k]) return true;
return false;

缺陷:時間 O(n³),空間 O(1)。大數據超時,未利用題目「只需存在性」特性。

正解:貪心維護兩個候選值 — O(n) 時間、O(1) 空間

核心思想:遍歷數組,維護兩個變量:

  • first:迄今遇到的最小值 (潛在三元組第一個數)。
  • second:迄今遇到的、大於 first 的最小值 (潛在三元組第二個數)。

一旦遇到數字 `num > second`,即構成 `first < second < num`,直接返回 `true`。遍歷結束未觸發則返回 `false`。

代碼實現

public boolean increasingTriplet(int[] nums) {
    int first = Integer.MAX_VALUE;
    int second = Integer.MAX_VALUE;
    
    for (int num : nums) {
        if (num <= first) {
            first = num;           // 更新最小值
        } else if (num <= second) {
            second = num;          // 更新中間值 (比 first 大但盡可能小)
        } else { // num > second
            return true;           // 找到 third,三元組成立
        }
    }
    return false;
}

算法正確性證明 (直觀理解)

  1. first 永遠記錄「截止當前、能作為三元組起始的最小值」。越小越容易滿足後續遞增。
  2. second 記錄「截止當前、能作為三元組中間值的最小值」(前提是已有 `first`)。它只在 `num > first` 時才可能更新,且取最小的符合條件者,留最大空間給第三個數。
  3. 當出現 `num > second` 時,根據定義必然存在先前的 `first < second`,且索引順序滿足 `i < j < k`,三元組確定存在。
  4. 即使 `first` 後續被更新為更小值 (索引在 `second` 之後),也不影響已經確立的 `second` 的有效性,因為我們只需「存在」一組合法索引,而非追蹤具體索引。

擴展:尋找長度為 k 的遞增子序列 (LIS 變體)

同理維護大小為 `k-1` 的數組 `candidates[]`,遍歷更新。時間 O(n log k) (二分查找插入位置) 或 O(nk) (線性掃描)。空間 O(k)。本題 k=3 退化為 O(1) 空間。

總結對比

方法時間空間備註
三層循環暴力O(n³)O(1)超時
DP 最長遞增子序列 (LIS)O(n²)O(n)過度殺傷
貪心雙變量 (標準解)O(n)O(1)完美滿足要求
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved