leetcode_334.递增的三元子序列

题目

给定一个未排序的数组,判断这个数组中是否存在长度为 3 的递增子序列。

数学表达式如下:

如果存在这样的 i, j, k, 且满足 0 ≤ i < j < k ≤ n-1,
使得 arr[i] < arr[j] < arr[k],返回 true ; 否则返回 false 。

说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1) 。

示例 1:

输入: [1,2,3,4,5]
输出: true

示例 2:

输入: [5,4,3,2,1]
输出: false

思路

首先,新建两个变量 small 和 mid ,分别用来保存题目要我们求的长度为 3 的递增子序列的最小值中间值

接着,我们遍历数组,每遇到一个数字,我们将它和 small 和 mid 相比,

  • 若小于等于 small ,则替换 small;
  • 否则,若小于等于 mid,则替换 mid;
  • 否则,若大于 mid,则说明我们找到了长度为 3 的递增数组!(已确认了第一、二个数,第三个数一但确定,则大势定矣

求解过程中有个问题:

当已经找到了长度为 2 的递增序列,这时又来了一个比 small 还小的数字,为什么可以直接替换 small 呢,这样 small 和 mid 在原数组中并不是按照索引递增的关系呀?
例如: 检测完了第一二号元素,此时small = 3, mid = 5, 这时检测到了一个 “2”, 也就是说要用三号“2”将一号“1”替换,此时【small = 三号“2” mid = 二号“5”】,与题意不符。

为了解释这个问题,我们假如当前的 small 和 mid 为 [3, 5],这时又来了个 1。假如我们不将 small 替换为 1,那么,当下一个数字是 2,后面再接上一个 3 的时候,我们就没有办法发现这个 [1,2,3] 的递增数组了!也就是说,我们替换最小值,是为了后续能够更好地更新中间值!

且,即使我们更新了 small ,这个 small 在 mid 后面,没有严格遵守递增顺序,但它却可以证明,有一个比 small 大比 mid 小的值出现在 mid 之前。因此,当后续出现比 mid 大的值的时候,我们一样可以通过当前 small 和 mid 推断的确存在着长度为 3 的递增序列。 所以,这样的替换并不会干扰我们后续的计算!

前两段有点拗口,但是注意一句话可以迎刃而解:

有一个比 small 大比 mid 小的值出现在 mid 之前

这是保证程序原理不出错的关键。

代码如下:

class Solution {
public:
    bool increasingTriplet(vector<int>& nums) {
        int len = nums.size();
        if (len < 3) return false;
        int small = INT_MAX, mid = INT_MAX;
        for (auto num : nums) { // 定义num变量,将它的指针顺次指向nums数组的每个元素(关于auto,百度一下,你就知道)
        	//接下来三行是程序主体
            if(num <= small) small = num;
            else if(num <= mid) mid = num; 
            else if(num > mid) return true; //发现了第三个数,大功告成
        }
        return false;    
    }
};
发布了3 篇原创文章 · 获赞 4 · 访问量 66

猜你喜欢

转载自blog.csdn.net/qq_45698847/article/details/105181238