您的位置首页 >人工智能 >

Rust 实现 LeetCode334 递增的三元子序列,贪心 O (n) 零额外空间题解

LeetCode334 的目标是判断数组里是否存在下标 i

题目基础信息

  • 题号:LeetCode 334,Increasing Triplet Subsequence
  • 难度:Medium
  • 输入约束:数组长度 [1, 5*10^5];元素范围 -2^31 ~ 2^31 -1
  • 核心要求:子序列,不需要连续;严格递增;只需要判断存在,不用输出下标
  • 进阶要求:O (n) 时间,O (1) 额外空间

多种方案对比表

方案时间复杂度空间复杂度适合场景缺点
贪心双变量(推荐 Rust 写法)O(n)O(1)大数据、面试最优解不容易直观理解 first 更新后顺序的问题
双向遍历(左右预存最值)O(n)O(n)新手理解逻辑占用数组,不满足进阶空间要求
DP(LIS)O(n²)O(n)通用最长递增子序列思路大数据直接超时
暴力三层循环O(n³)O(1)极小数组演示数据量稍微变大直接超时
贪心 + 二分 LISO(n log n)O(n)需要拓展找长度 k 的递增子序列空间不是常数

贪心算法完整逻辑

整个思路的核心不是固定锁定某一组 i、j,而是持续维护最容易匹配成功的 “递增二元对”。first 是当前见过最小的数字,second 是在 first 之后、比 first 大里面尽可能小的值。如果后续出现一个数字大于 second,就说明一定存在 i

  1. 初始化 first、second 为 i32 的最大值 i32::MAX
  2. 依次取出数组每一个 num:
  3. 如果 num <= first:更新 first = num,拿到更小的第一个候选
  4. 如果 num <= second,同时 num> first:更新 second = num,拿到更优的第二个候选
  5. 如果 num > second:直接 return true,三元组找到
  6. 遍历全部结束,没有触发上面分支,返回 false

重点:就算 first 更新到 second 的后面,也不影响正确性,second 记录的是历史上一个合法二元对的第二个值,只要后面出现更大的值,就一定存在合法顺序。

Rust 可提交完整代码

pub fn increasing_triplet(nums: Vec) -> bool {

let mut first = i32::MAX;

let mut second = i32::MAX;

for &num in &nums {

if num <= first {

first = num;

} else if num <= second {

second = num;

} else {

return true;

}

}

false

}

配套测试用例:

  • increasing_triplet(vec![1,2,3,4,5]) → true
  • increasing_triplet(vec![5,4,3,2,1]) → false
  • increasing_triplet(vec![2,1,5,0,4,6]) → true

分步走样例推演([2,1,5,0,4,6])

  1. num=2:2 <= MAX,first=2
  2. num=1:1 <= 2,first=1
  3. num=5:5>1,5<=MAX,second=5
  4. num=0:0 <= 1,first=0
  5. num=4:4>0,4<=5,second=4
  6. num=6:6>4,触发 return true

高频坑点清单

  • 必须是 <=,不能写成 <:如果写成严格小于,重复数字会错误更新 second,比如 [1,1,1,1] 会误判
  • 不要误以为 first 一定在 second 前面:first 可以更新到 second 后面,但是 second 代表历史上合法二元对,算法依然成立
  • 数组长度小于 3 直接返回 false:代码天然兼容,因为循环不会命中第三个分支
  • 负数边界:Rust 使用 i32,初始化 MAX 可以覆盖全部输入区间,不需要额外处理负数
  • 不要尝试保存下标:保存下标会增加逻辑复杂度,这道题只关心是否存在,不需要下标

【常见问题】

问题 1:Rust 写 LeetCode334 递增的三元子序列,贪心方案为什么只用 first、second 两个变量就够用?

回答 1:LeetCode334 贪心解法里 first 维护遍历到的最小值,second 维护大于 first 的最小候选,只要遇到比 second 更大的值,就代表存在递增三元子序列,不需要记录完整下标,一趟扫描完成,满足 O (1) 空间。

问题 2:LeetCode334 递增的三元子序列贪心逻辑,当 first 更新到 second 之后,算法为什么不会出错?

回答 2:LeetCode334 的 second 保存的是历史上一组合法递增二元对的第二个数,就算后面 first 更新到 second 的后方,只要后续数字大于 second,就一定能找到满足 i

问题 3:Rust 实现 LeetCode334 递增的三元子序列,如果把判断条件 num <= first 改成 num < first 会出现什么问题?

回答 3:如果改成严格小于,遇到连续相同数字,比如数组 [1,1,1],不会更新 first、second,有可能出现逻辑异常,相等元素不能作为递增链延伸,所以这里必须使用 <=。

问题 4:LeetCode334 递增的三元子序列,双向遍历方案为什么不满足题目的进阶要求?

回答 4:双向遍历需要提前预处理左侧最小值数组、右侧最大值数组,额外空间是 O (n),而 LeetCode334 的进阶要求是 O (1) 额外空间,因此面试优先推荐 Rust 双变量贪心版本。

【参考资料】

[2026-11-14](Rust LeetCode334 算法题解)阿里云开发者社区

[2026-11-14](334. 递增的三元子序列 官方题解)力扣 LeetCode

[2026-11-10](Increasing Triplet Subsequence Rust greedy solution)LeetCode The Hard Way

[2026-10-20](LeetCode 334 贪心思路深度拆解)吴师兄学算法

[2025-11-18](LeetCode 334 递增三元子序列边界与易错点)hueco.tistory.com

【免责声明】

本文内容整理自 LeetCode 官方题解、Rust 社区提交样例、算法公开博客;LeetCode334 递增的三元子序列贪心思路存在理解门槛,该 Rust 代码仅适用于算法练习与面试刷题;不同版本的 Rust 标准库、在线判题环境对整数边界处理逻辑一致,但在生产业务中如果需要拓展到更长递增子序列,推荐改用贪心 + 二分的 LIS 方案,本文不构成生产代码直接复用的保证。

今日大家都在搜的词: