题目描述:
给你一个整数数组 nums ,判断这个数组中是否存在长度为 3 的递增子序列。
如果存在这样的三元组下标 (i, j, k) 且满足 i < j < k ,使得 nums[i] < nums[j] < nums[k] ,返回 true ;否则,返回 false 。
样例:
方法一:
class Solution {
public:
bool increasingTriplet(vector<int>& nums) {
int n = nums.size();
vector<int> premin(n), reamax(n);
premin[0] = nums[0];
reamax[n - 1] = nums[n - 1];
for (int i = 1; i < n; i++)
{
premin[i] = min(premin[i - 1], nums[i]);
}
for (int i = n - 2; i >= 0; i--)
{
reamax[i] = max(reamax[i + 1], nums[i]);
}
for (int i = 1; i < n - 1; i++)
{
if (premin[i] < nums[i] && nums[i] < reamax[i])
{
return true;
}
}
return false;
}
};
挺明显的前缀最小、后缀最大的思路,居然卡了好一会,然后想用双指针试一下时间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;
}
};
咳咳,原来不用什么前缀后缀啊,直接一次遍历即可,一个数记录最小值,另一个数记录第二小的值。
这里有个很巧妙的地方,就是if的顺序,这个很关键,first始终记录的是数列中最小的一个数字,而second只要被更新了一次,就说明前面的序列中有一个递增的二元子序列(first,second),因此只要后续碰到一个比second还大的数字,就说明存在一个递增的三元子序列!
例如对于5,6,1,7这样的例子:
①遍历到6时将会更新second,此时first为5,second为6,说明前面存在一个递增的二元子序列(5, 6)
②虽然遍历到1时first的值会被更新为1,但是second的值依旧是6,只要后续出现比6大的数字x,就能够说明存在一个递增的三元子序列(5, 6, x)