标题:递增的三元子序列
出处:334. 递增的三元子序列
6 级
给你一个整数数组 nums \texttt{nums} nums,如果存在这样的三元组下标 (i, j, k) \texttt{(i, j, k)} (i, j, k) 满足 i < j < k \texttt{i < j < k} i < j < k 和 nums[i] < nums[j] < nums[k] \texttt{nums[i] < nums[j] < nums[k]} nums[i] < nums[j] < nums[k],返回 true \texttt{true} true;否则,返回 false \texttt{false} false。
示例 1:
输入: nums = [1,2,3,4,5] \texttt{nums = [1,2,3,4,5]} nums = [1,2,3,4,5]
输出: true \texttt{true} true
解释:任何 i < j < k \texttt{i < j < k} i < j < k 的三元组都满足题意。
示例 2:
输入: nums = [5,4,3,2,1] \texttt{nums = [5,4,3,2,1]} nums = [5,4,3,2,1]
输出: false \texttt{false} false
解释:不存在满足题意的三元组。
示例 3:
输入: nums = [2,1,5,0,4,6] \texttt{nums = [2,1,5,0,4,6]} nums = [2,1,5,0,4,6]
输出: true \texttt{true} true
解释:三元组 (3, 4, 5) \texttt{(3, 4, 5)} (3, 4, 5) 满足题意,因为 nums[3] = 0 < nums[4] = 4 < nums[5] = 6 \texttt{nums[3] = 0 < nums[4] = 4 < nums[5] = 6} nums[3] = 0 < nums[4] = 4 < nums[5] = 6。
你能实现时间复杂度为 O(n) \texttt{O(n)} O(n),空间复杂度为 O(1) \texttt{O(1)} O(1) 的解决方案吗?
这道题中,数组 nums \textit{nums} nums 的长度最大为 5 × 1 0 5 5 \times 10^5 5×105,暴力解法会超出时间限制,必须使用复杂度较低的解法。
由于题目要寻找递增的三元子序列,只有当数组的长度大于等于 3 3 3 时,才存在三元子序列,因此当数组的长度小于 3 3 3 时,直接返回 false \text{false} false 即可。
当数组的长度大于等于 3 3 3 时,只需要遍历数组一次,使用 O ( n ) O(n) O(n) 时间和 O ( 1 ) O(1) O(1) 的空间即可判断是否存在递增的三元子序列。维护两个变量 firstNum \textit{firstNum} firstNum 和 secondNum \textit{secondNum} secondNum 分别存储递增三元子序列的第一个数和第二个数,任何时候都满足 firstNum < secondNum \textit{firstNum}<\textit{secondNum} firstNum<secondNum,如果遍历过程中遇到一个大于 secondNum \textit{secondNum} secondNum 的元素,即找到了一个递增三元子序列。
具体做法是,初始化 firstNum = nums [ 0 ] \textit{firstNum}=\textit{nums}[0] firstNum=nums[0], secondNum = + ∞ \textit{secondNum}=+\infty secondNum=+∞(代码中使用整型的最大值表示 + ∞ +\infty +∞)。由于 nums [ 0 ] \textit{nums}[0] nums[0] 已经赋值给 firstNum \textit{firstNum} firstNum,因此从下标 1 1 1 开始遍历数组 nums \textit{nums} nums。对于遍历到的元素 num \textit{num} num,进行如下操作:
如果 num > secondNum \textit{num}>\textit{secondNum} num>secondNum,则 ( firstNum , secondNum , num ) (\textit{firstNum},\textit{secondNum},\textit{num}) (firstNum,secondNum,num) 即为同时满足下标递增和元素值递增的递增三元子序列,返回 true \text{true} true;
如果 firstNum < num ≤ secondNum \textit{firstNum}<\textit{num} \le \textit{secondNum} firstNum<num≤secondNum,则如果在 num \textit{num} num 的后面存在 num 2 \textit{num}_2 num2 满足 num 2 > num \textit{num}_2>\textit{num} num2>num,则 ( firstNum , num , num 2 ) (\textit{firstNum},\textit{num},\textit{num}_2) (firstNum,num,num2) 即为一个递增三元子序列,由于 num ≤ secondNum \textit{num} \le \textit{secondNum} num≤secondNum,因此将 num \textit{num} num 的值赋给 secondNum \textit{secondNum} secondNum,只要在 num \textit{num} num 的后面找到一个元素大于更新后的 secondNum \textit{secondNum} secondNum,即找到一个递增三元子序列;
如果 num ≤ firstNum \textit{num} \le \textit{firstNum} num≤firstNum,则将 num \textit{num} num 的值赋给 firstNum \textit{firstNum} firstNum。
上述做法中,如果找到一个递增三元子序列,则三个元素值一定是递增顺序,那么下标是否也满足递增顺序?答案是肯定的。理由如下:
当找到 num > secondNum \textit{num}>\textit{secondNum} num>secondNum 时, num \textit{num} num 一定在 secondNum \textit{secondNum} secondNum 的后面,即 num \textit{num} num 的下标一定大于 secondNum \textit{secondNum} secondNum 的下标;
当 secondNum \textit{secondNum} secondNum 被更新时,更新后的 secondNum \textit{secondNum} secondNum 一定在 firstNum \textit{firstNum} firstNum 的后面,即 secondNum \textit{secondNum} secondNum 的下标一定大于 firstNum \textit{firstNum} firstNum 的下标;
当 firstNum \textit{firstNum} firstNum 被更新时,虽然更新后的 firstNum \textit{firstNum} firstNum 在 secondNum \textit{secondNum} secondNum 的后面,但是更新前的 firstNum ′ \textit{firstNum}' firstNum′ 满足 firstNum ′ < secondNum \textit{firstNum}'<\textit{secondNum} firstNum′<secondNum 且 firstNum ′ \textit{firstNum}' firstNum′ 在 secondNum \textit{secondNum} secondNum 的前面,即 firstNum ′ \textit{firstNum}' firstNum′ 的下标小于 secondNum \textit{secondNum} secondNum 的下标。
因此,虽然没有记录三个元素的具体下标值,但是可以保证三个元素的下标满足递增顺序。
class Solution {
public boolean increasingTriplet(int[] nums) {
int length = nums.length;
if (length < 3) {
return false;
}
int firstNum = nums[0], secondNum = Integer.MAX_VALUE;
for (int i = 1; i < length; i++) {
int num = nums[i];
if (num > secondNum) {
return true;
} else if (num > firstNum) {
secondNum = num;
} else {
firstNum = num;
}
}
return false;
}
}
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。遍历数组 nums \textit{nums} nums 一次,遍历过程中维护 firstNum \textit{firstNum} firstNum 和 secondNum \textit{secondNum} secondNum 的值,对于每个位置,维护两个变量的时间复杂度是 O ( 1 ) O(1) O(1),因此总时间复杂度是 O ( n ) O(n) O(n)。
空间复杂度: O ( 1 ) O(1) O(1)。