Medium
题目描述
给你一个整数数组 nums ,判断这个数组中是否存在长度为 3 的递增子序列。
如果存在这样的三元组下标 (i, j, k) 且满足 i < j < k 和 nums[i] < nums[j] < nums[k] ,返回 true ;否则,返回 false 。
示例 1:
输入:nums = [1,2,3,4,5]
输出:true
解释:任何满足 i < j < k 的三元组都是有效的。
示例 2:
输入:nums = [5,4,3,2,1]
输出:false
解释:不存在满足条件的三元组。
示例 3:
输入:nums = [2,1,5,0,4,6]
输出:true
解释:有效的三元组是 (1, 4, 5),因为 nums[1] == 1 < nums[4] == 4 < nums[5] == 6。
提示:
1 <= nums.length <= 5 * 10^5-2^31 <= nums[i] <= 2^31 - 1
**进阶:**你能实现时间复杂度为 O(n) ,空间复杂度为 O(1) 的解决方案吗?
解题思路
解题思路
这道题要求找到一个长度为3的严格递增子序列。关键是理解题目只需要判断是否存在,而不需要找出具体的三元组。
方法一:贪心算法(推荐)
核心思想是维护两个变量:
first:遇到的最小值second:在找到first之后遇到的最小值(且大于first)
当我们遍历数组时:
- 如果当前数字小于等于
first,更新first - 如果当前数字大于
first但小于等于second,更新second - 如果当前数字大于
second,说明找到了递增三元组
这个方法的巧妙之处在于,即使后续更新了first,之前的second仍然有效,因为它代表了"在某个更小值之后的第二小值"。
方法二:动态规划
可以用两个数组分别记录每个位置左边的最小值和右边的最大值,然后判断是否存在位置使得左最小值 < 当前值 < 右最大值。但这需要O(n)的额外空间。
贪心算法是最优解,时间复杂度O(n),空间复杂度O(1)。
代码实现
class Solution {
public:
bool increasingTriplet(vector<int>& nums) {
int first = INT_MAX, second = INT_MAX;
for (int num : nums) {
if (num <= first) {
first = num;
} else if (num <= second) {
second = num;
} else {
return true;
}
}
return false;
}
};
class Solution:
def increasingTriplet(self, nums: List[int]) -> bool:
first = float('inf')
second = float('inf')
for num in nums:
if num <= first:
first = num
elif num <= second:
second = num
else:
return True
return False
public class Solution {
public bool IncreasingTriplet(int[] nums) {
int first = int.MaxValue, second = int.MaxValue;
foreach (int num in nums) {
if (num <= first) {
first = num;
} else if (num <= second) {
second = num;
} else {
return true;
}
}
return false;
}
}
var increasingTriplet = function(nums) {
let first = Infinity, second = Infinity;
for (let num of nums) {
if (num <= first) {
first = num;
} else if (num <= second) {
second = num;
} else {
return true;
}
}
return false;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 只需要遍历数组一次 |
| 空间复杂度 | O(1) | 只使用了常数个额外变量 |