8、递增的三元子序列

52 阅读3分钟

原题力扣《递增的三元子序列》

难度中等

题目:

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

如果存在这样的三元组下标 (i, j, k) 且满足 i < j < k ,使得 nums[i] < nums[j] < nums[k] ,返回 true ;否则,返回false 。

示例 1:

输入:nums = [1,2,3,4,5]
输出:true
解释:任何 i < j < k 的三元组都满足题意

示例 2:

输入:nums = [5,4,3,2,1]
输出:false
解释:不存在满足题意的三元组

示例 3:

输入:nums = [2,1,5,0,4,6]
输出:true
解释:三元组 (3, 4, 5) 满足题意,
因为 nums[3] == 0 < nums[4] == 4 < nums[5] == 6

提示:

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

进阶:你能实现时间复杂度为 O(n) ,空间复杂度为 O(1) 的解决方案吗?

解题:

个人:

关键:硬解的

  1. 条件:i < j < k ,使得 nums[i] < nums[j] < nums[k] ,返回 true
  2. 嵌套循环,先找 i
  3. 再循环找 j,j 找到后再循环找 k
  4. 三层嵌套循环
var increasingTriplet = function (nums) {
  let i = 0;
  let = j = k = 0;
  const len = nums.length;

  for (; i < len; i++) {
    for (let index = i + 1; index < len; index++) {
      if (nums[index] > nums[i]) {
        j = index;

        for (let index = j + 1; index < len; index++) {
          if (nums[index] > nums[j]) {
            k = index;
            break;
          }
        }

        if (k) {
          break;
        }
      }
    }

    if (j === 0) {
      continue;
    }

    if (j > 0 && k > 0) {
      break;
    }
  }
  return Boolean(j > 0 && k > 0);
};

Case 通过,但提交后超长数据运行报错

耗时:40 min

官方:

关键1:双循环

思路1:1<= i <= len - 1,存在 n[左侧最小] < n[i] < n[右侧最大]

将数据分为两块,LMin 存放下标 i 时,左侧最小的、RMax 存放下标 i 时,右侧最大的

最后判断是否满足 LMin[i] < n[i] < RMax[i]

var increasingTriplet = function (nums) {
  const len = nums.length;

  const LMin = [];
  const RMax = [];

  LMin[0] = nums[0];
  for (let index = 1; index < nums.length; index++) {
    const element = nums[index];
    LMin[index] = Math.min(LMin[index - 1], element);
  }

  RMax[len - 1] = nums[len - 1];
  for (let index = len - 2; index >= 0; index--) {
    const element = nums[index];
    RMax[index] = Math.max(RMax[index + 1], element);
  }

  for (let index = 0; index < nums.length; index++) {
    const element = nums[index];
    if (element > LMin[index] && element < RMax[index]) {
      return true;
    }
  }
  return false;
};

关键2:贪心

思路2:初始设置 first = nums[0];second = 无穷大;现在循环找 third

  1. 若 third > second,则找到了,返回 true
  2. 若 third < second 但 third > first,则 second = third,继续循环找 third
  3. 若 third < first,则 first = third,继续循环找 third(虽然 first 在 second 之后了,但在 second 之前,存在过老的 first 并小于 second)

举例:[3, 2, 4, 1, 7, 6, 9]

1 次时:
  first = nums[0] = 3; second = Number.MAX_VALUE; third = nums[1] = 2
判断 third,满足 third < first,则 first = third = 22 次时:
  first = 2; second = Number.MAX_VALUE; third = nums[2] = 4
判断 third,满足 second > third > first,则 second = third = 43 次时:
  first = 2; second = 4; third = nums[3] = 1
判断 third,满足 third < first,则 first = third = 14 次时:
  first = 1; second = 4; third = nums[4] = 7
判断 third,满足 third > second,则找到了,终止循环,并返回 true

此时找到的三元下标为:x,2,4,对应值为 num[x],4,7
其中的 x 为下标 2 之前的任意一个,即老 first 用过的下标 0,1
0,2,4 对应值为 3,4,7
1,2,4 对应值为 2,4,7
var increasingTriplet = function (nums) {
  let first = nums[0];
  let second = Number.MAX_VALUE;

  for (let index = 0; index < nums.length; index++) {
    const third = nums[index];

    if (third > second) return true;
    else if (third > first) second = third;
    else first = third;
  }

  return false;
};

总结:

上一道题目才做双循环的,就给忘了,让后又变成硬解了。

以后遇到数组的,先考虑双指针、再考虑能否生成两个数组,最后再硬解