递增的三元子序列
1.题目链接:
334. 递增的三元子序列
2.原题描述:
给你一个整数数组 nums ,判断这个数组中是否存在长度为 3 的递增子序列。
如果存在这样的三元组下标 (i, j, k) 且满足 i < j < k ,使得 nums[i] < nums[j] < nums[k] ,返回 true ;否则,返回 false 。
3.相关算法
贪心算法:
通过维护两个数,不断更新这两个数,来判断是否存在长度为 3 的递增子序列。
时间复杂度为 O(n),空间复杂度为 O(1)。
动态规划算法:
维护两个数组 dp1 和 dp2,其中 dp1[i] 表示以 nums[i] 为结尾的长度为 1 的递增子序列的最小值,dp2[i] 表示以 nums[i] 为结尾的长度为 2 的递增子序列的最小值。
遍历数组 nums,对于每个数 nums[i],更新 dp1[i] 和 dp2[i],然后判断是否存在长度为 3 的递增子序列。时间复杂度为O(n),空间复杂度为O(n)。
4.本题主要思路
因为是找长度为 3 的递增子序列,所以需要记录两个数:第一个数和第二个数。遍历数组,如果当前数大于第二个数,则必定存在一个递增子序列。
如果当前数小于等于第二个数但大于第一个数,那么可以更新第二个数为当前数。如果当前数小于第一个数,则将第一个数更新为当前数。
最后,如果找到了一个大于第二个数的数,说明存在递增子序列,返回 true,否则返回 false
5.源码分析
贪心算法:
class Solution {
public boolean increasingTriplet(int[] nums) {
int first = Integer.MAX_VALUE, second = Integer.MAX_VALUE; // 1
for(int i = 0;i<nums.length;++i){
if(nums[i]>second){ // 2
return true;
}else if(nums[i]>first){ // 3
second = nums[i];
}else{ // 4
first = nums[i];
}
}
return false; // 5
}
}
- 创建两个需要维护的前两个比较小的数
- for循环遍历,当该数大于第二大的数时则存在三元递增子序列,返回结果true
- 该数小于第二大的数,大于第一大的数,则将第二大的数替换成该数
- 该数小于第一小的数,则将第一小的数替换成该数
- for循环遍历完都没有返回相应的结果,则表明没有符合题目要求的三元子序列,最后返回false
动态规划:
class Solution {
public boolean increasingTriplet(int[] nums) {
int n = nums.length;
if (n < 3) {
return false;
}
int[] dp1 = new int[n];
int[] dp2 = new int[n];
Arrays.fill(dp1, Integer.MAX_VALUE);
Arrays.fill(dp2, Integer.MAX_VALUE);
dp1[0] = nums[0];
for (int i = 1; i < n; i++) {
dp1[i] = Math.min(dp1[i - 1], nums[i]);
}
dp2[1] = nums[0];
for (int i = 2; i < n; i++) {
dp2[i] = Math.min(dp2[i - 1], nums[i - 1]);
if (nums[i] > dp2[i]) {
if (nums[i] > dp1[i - 1]) {
return true;
}
}
}
return false;
}
}