334. Increasing Triplet Subsequence

题目:

Given an integer array nums, return true if there exists a triple of indices (i, j, k) such that i < j < k and nums[i] < nums[j] < nums[k]. If no such indices exists, return false.

 

Example 1:

Input: nums = [1,2,3,4,5]
Output: true
Explanation: Any triplet where i < j < k is valid.

Example 2:

Input: nums = [5,4,3,2,1]
Output: false
Explanation: No triplet exists.

Example 3:

Input: nums = [2,1,5,0,4,6]
Output: true
Explanation: The triplet (3, 4, 5) is valid because nums[3] == 0 < nums[4] == 4 < nums[5] == 6.

 

Constraints:

  • 1 <= nums.length <= 10^5
  • -231 <= nums[i] <= 2^31 - 1

Follow up: Could you implement a solution that runs in O(n) time complexity and O(1) space complexity?

 

思路1:

这题其实相当于找最长subsequence的简化版,只要找到长度大于等于3的即可。数据量在10的5次,但是试了一下O(n^{^{2}})的DP也能过,基本思路就是二重循环找当前数前面的最长subsequence,这里就不写了。写一下O(nlogn)的最长subsequence的方法。建一个数组res,不用初始化。然后遍历原数组,如果res为空则直接塞入,否则二分法判断当前数字应该在res中的位置,这里我们用lower_bound即可。如果判断完了应该在res的最尾,则直接push_back,否则就用当前数字去替换原有数字。这里虽然会有后面的更小值替换了前面的较大的值导致其实不是真实的子序列(会有乱序),但是因为只是求长度,所以替换产生的乱序并不会破坏答案正确性。当然这种写法不符合follow up的时间复杂度和空间复杂度。

 

 

 

代码1:

bool increasingTriplet(vector<int>& nums) {
    vector<int> res;
    for (auto i : nums)
    {
        auto itr = lower_bound(res.begin(), res.end(), i);
        if (itr == res.end())
            res.push_back(i);
        else
            *itr = i;
        if (res.size() >= 3)
            return true;
    }
    return false;
}
 

 

 

思路2:

只要找三个数,这里我们可以用两个额外数组去存每个数左边的最小值和右边的最大值,然后再对原数组进行遍历,去看是否满足不等式。这里的话同样需要额外空间复杂度,但是时间复杂度被降低,只需要遍历数组三次即可。当然,时间复杂度符合follow up,但是空间复杂度不符合。

 

 

代码2:

class Solution {
public:
    bool increasingTriplet(vector<int>& nums) {
        int n=nums.size();
        if(n<3)
            return false;
        vector<int> l(n,nums[0]), r(n,nums[n-1]);
        for(int i=1;i<n;i++)
            l[i]=min(l[i-1],nums[i]);
        for(int i=n-2;i>=0;i--)
            r[i]=max(r[i+1],nums[i]);
        for(int i=0;i<n;i++)
        {
            if((l[i]<nums[i])&&(nums[i]<r[i]))
                return true;
        }
        return false;
        
    }
};

 

 

思路3:

因为只需要三个数,想象一个数轴,我们用a和b记录前两个数,只要我们一直保持a<b存在,那么当我们找到c>b时,其实就已经完成了。这里设置一个if elseif else的选择,比较巧妙。先初始化a和b,设置最大值,然后遍历数组,每次先看a,如果小于等于a则赋值给a,如果大于a就看b,如果小于等于b就赋值给b,如果比b还大则我们已经找到了三个数,可以直接返回true了。这里注意一定要小于等于,因为如果if 小于a,然后else if小于b,则等于a或者等于b会落在最后的else区域,这样的话如果数组是[8,8,8,8,8,8],会落在else而返回true。因此等于的情况一定要直接去替换。

 

 

代码3:

class Solution {
public:
    bool increasingTriplet(vector<int>& nums) {
        int a=INT_MAX, b=INT_MAX;
        for(auto i:nums)
        {
            if(i<=a)
                a=i;
            else if(i<=b)
                b=i;
            else
                return true;
        }
        return false;
    }
};

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值