[LeetCode]334. Increasing Triplet Subsequence

递增的三元组

Posted by JinFei on February 16, 2020

题目描述

Given an unsorted array return whether an increasing subsequence of length 3 exists or not in the array.

Formally the function should: Return true if there exists i, j, k such that arr[i] < arr[j] < arr[k] given 0 ≤ i < j < k ≤ n-1 else return false.

NOTE

Your algorithm should run in O(n) time complexity and O(1) space complexity.

Example1:

  Input: [1,2,3,4,5]
    Output: true

Example2:

  Input: [5,4,3,2,1]
    Output: false

解题思路

  • 这道题找出 存不存在 递增的三元组 (这里的三元组不一定是挨着的)
  • 我们可以两个数组作为辅助
  • 其中一个是前项数组,存 i 之前的最小值 (我们把nums[0]初始化dp_Min[0] -> min)
  • 其中一个是后项数组,存 i 之后的最大值 (我们将nums最后一个值 初始化)
  • 然后遍历这个数组,如果此时的 num > dp_Min[i] && num < dp_Max[i] 就找到了一个递增的三元组
class Solution {
public:
    bool increasingTriplet(vector<int>& nums) {
        if(nums.size() < 3){
            return false;
        }
        int n = nums.size();
        vector<int> forward(n, nums[0]);
        vector<int> backward(n, nums.back());
        for(int i = 1; i < n; i++){
            forward[i] = min(forward[i - 1], nums[i]);
        }
        for(int i = n - 2; i >= 0; i--){
            backward[i] = max(backward[i + 1], nums[i]);
        }
        for(int i = 0; i < n; i++){
            if(nums[i] > forward[i] && nums[i] < backward[i]){
                return true;
            }
        }
        return false;
    }
};

解题思路

  • 这道题找出 存不存在 递增的三元组 (这里的三元组不一定是挨着的)
  • 我们可以两个数组作为辅助
  • 其中一个是前项数组,存 i 之前的最小值 (我们把nums[0]初始化dp_Min[0] -> min)
  • 其中一个是后项数组,存 i 之后的最大值 (我们将nums最后一个值 初始化)
  • 然后遍历这个数组,如果此时的 num > dp_Min[i] && num < dp_Max[i] 就找到了一个递增的三元组
class Solution {
public:
    bool increasingTriplet(vector<int>& nums) {
        if(nums.size() < 3){
            return false;
        }
        int n = nums.size();
        vector<int> forward(n, nums[0]);
        vector<int> backward(n, nums.back());
        for(int i = 1; i < n; i++){
            forward[i] = min(forward[i - 1], nums[i]);
        }
        for(int i = n - 2; i >= 0; i--){
            backward[i] = max(backward[i + 1], nums[i]);
        }
        for(int i = 0; i < n; i++){
            if(nums[i] > forward[i] && nums[i] < backward[i]){
                return true;
            }
        }
        return false;
    }
};

简单但难想的解题思路

  • 使用两个指针m1和m2,初始化为整型最大值
  • 我们遍历数组,如果m1大于等于当前数字,则将当前数字赋给m1;
  • 如果m1小于当前数字且m2大于等于当前数字,那么将当前数字赋给m2,一旦m2被更新了,说明一定会有一个数小于m2,那么我们就成功的组成了一个长度为2的递增子序列
  • 所以我们一旦遍历到比m2还大的数,我们直接返回ture。
  • 如果我们遇到比m1小的数,还是要更新m1,有可能的话也要更新m2为更小的值,毕竟m2的值越小,能组成长度为3的递增序列的可能性越大
    // Idea is keep track of smallest two numbers, ensuring min1 < min2.
    // If at any point we find a number 'n', such that n > min1 and n > min2, that makes a triplet
    // else if n < min1, min1 = n, or if n > min1 and n < min2, min2 = n.
    // If we are not able to find a triplet till position 'i', we can safely update the min values to even smaller
    // value just making sure that min1 < min2.
    bool increasingTripletTwoPointers(vector<int>& nums) {
        // keeps track of smallest two numbers, such that min1 < min2
        int min1 = numeric_limits<int> :: max(), min2 = numeric_limits<int> :: max();
        
        for(const int& num : nums) {
            // if current is smaller/equal(otherwise same number might go to min2) than min1, update it
            if(num <= min1)
                min1 = num;
            // current is greater than min1 but smaller/equal than min2, that makes min1 < min2 > num,
            // so update min2
            else if(num <= min2)
                min2 = num;
            // current is greater than min2, min1 < min2 < num
            else if(num > min2)
                return true;
        }
        return false;
    }