LeetCode/solutions/334. Increasing Triplet Subsequence.md
2019-12-08 22:19:02 +08:00

2.3 KiB
Raw Blame History

334. Increasing Triplet Subsequence

思路

这道题让我们求一个无序数组中是否包含一个三个元素的递增子序列并要求时间复杂度O(n)空间复杂度O(1)。

时间复杂度O(n)很好满足但是空间复杂度要想O(1)就有点难想了。 因为我们可以用两个dp数组dp1和dp2可以优化成只用一个dp数组dp1[i]和dp2[i]分别代表nums[i]前面的最小值和后面的最大值, 然后再判断是否存在dp1[i] < nums[i] < dp2[i]就可以了这种方法时间复杂度是满足的但是空间复杂度为O(n),不满足题意。

我们从前往后遍历nums数组定义

  • m2为到目前为止最有可能构成三元递增序列第二个元素的候选者即需满足m2尽可能小且在m2之前存在比m2小的数。

这样定义之后如果我们一旦遇到某个数nums[i]比m2大说明找到了三元递增序列。问题关键在于如何维持m2。

为此,我们需要再

  • 定义一个数m1表示到目前为止最有可能构成三元递增序列第一个元素的候选者也即到目前为止的最小值

需要注意的是,前面说了在m2之前一定存在比m2小的数但这个数不一定是m1m1可能是m2之后的数例如nums=[3,4,1,6]当遍历完1后m2=4而m1=1网上绝大多数博客都没提及这一点。

更新m1和m2的方式为

  • 初始时设置 m1 = m2 = INT_MAX
  • nums[i] <= m1 说明遇到了更小的值,更新m1 = nums[1]即可这里的更新就是在m2前且比m2小的数不一定就是m1的原因
  • 否则,即nums[i] > m1说明在nums[i]之前肯定有一个数就是当前的m1比nums[i]小又因为我们想m2尽可能小所以如果nums[i] <= m2,应更新m2 = nums[i]
  • 否则说明nums[i] > m2找到了递增子序列return true。

这样空间复杂度就为O(1)了上述思路还可以推广到子序列长度为4、5...无非就是多开辟几个mx罢了。

C++

public:
    bool increasingTriplet(vector<int>& nums) {
        int m1 = INT_MAX, m2 = INT_MAX;
        
        for(int num: nums){
            if(num <= m1) m1 = num;
            else if(num <= m2) m2 = num;
            else return true;
        }
        return false;
    }
};