【LeetCode】334。三元部分列の増加

1.トピック

整数配列numsを指定して、この配列に長さ3の増加するサブシーケンスがあるかどうかを判別します。

そのようなトリプル添え字(i、j、k)があり、nums [i] <nums [j] <nums [k]となるようにi <j <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 <= 105
  • -231 <= nums [i] <= 231-1

高度:時間計算量O(n)と空間計算量O(1)のソリューションを実装できますか?

二、解く

1.動的計画

アイデア

改善するために、毎回現在の数よりも少ない要素の数を見つけます。

コード

class Solution {
    
    
    public boolean increasingTriplet(int[] nums) {
    
    
        int n = nums.length;
        int[] dp = new int[n];
        Arrays.fill(dp, 1);
        for (int i = 0; i < n; ++i) {
    
    
            for (int j = 0; j < i; ++j) {
    
    
                if (nums[j] < nums[i]) {
    
    
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
                if (dp[i] >= 3) return true;
            }
        }
        return false;
    }
}

時間計算量O(n 2)O(n ^ 2)O n2
時間計算量O(n)O(n)O n

2.前後にトラバースします

アイデア

定义:
forward[i]:从前向后遍历,保存[0, i]之间最小元素值。
backward[i]:从后向前遍历,保存[i, n - 1]间最大元素值。

例如:
nums[i]: 8 3 5 1 6
forwa[i]: 8 3 3 1 1
backw[i]:8 6 6 6 6

コード

class Solution {
    
    
    public boolean increasingTriplet(int[] nums) {
    
    
        int n = nums.length;
        if (n < 3) return false;
        int[] f = new int[n]; f[0] = nums[0];
        int[] b = new int[n]; b[n-1] = nums[n-1];
        for (int i = 1; i < n; i++) {
    
    
            f[i] = Math.min(f[i - 1], nums[i]);
        }
        for (int i = n - 2; i >= 0; i--) {
    
    
            b[i] = Math.max(b[i + 1], nums[i]);
        }
        for (int i = 0; i < n; i++) {
    
    
            if (f[i] < nums[i] && nums[i] < b[i]) return true;
        }
        return false;
    }
}

時間計算量O(n)O(n)O n
時間計算量O(n)O(n)O n

3.ダブルポインター

アイデア

質問:長さ2の増加するシーケンスが見つかった、とsmall小さな番号が来る、なぜそれを直接交換することができsmallsmallその和がされmidたインデックスインクリメントしませんか?

注:現在のsmall = 3およびmid = 5の場合、1が来ます。smallを1に置き換えないと、次の数値が2で、3が続く場合、[1を見つける方法はありません。 、2、3]配列をインクリメントしてください!言い換えると、最小値の置き換えは、後で中間値をより適切に更新することです。

また、小さくても更新する場合は、この小さな半ばの後ろに、厳密に昇順に準拠していますが、それは真実が多数存在することである意味はなかったnumsmall < num && num < midの最小midフロント。したがって、その後の発生が中間値、電流通過small、およびmid推論よりも大きい場合、実際には3のシーケンス長が増加します。したがって、この置換によって後続の計算が妨げられることはありません。

コード

class Solution {
    
    
    public boolean increasingTriplet(int[] nums) {
    
    
        int small = Integer.MAX_VALUE, mid = Integer.MAX_VALUE;
        for (int num : nums) {
    
    
            if (num <= small) small = num;
            else if (num <= mid) mid = num;
            else return true;
        }
        return false;
    }
}

時間計算量O(n)O(n)O n
時間計算量O(1)O(1)O 1

3、参照

1. C ++線形時間複雑さの詳細な分析、98%を破り
2 [334インクリメンタル三サブ】3つのアイデア(動的プログラミング+二重ポインタ+前後トラバーサル)が
3のpython3が存在するかどうかを調べるために一般的な状況に拡張されていますは長さnの昇順のサブシーケンスです
。4 。このような問題に取り組む私の方法。それについてどう考えるか?私の思考フローの説明
。5。私のJavaソリューションはトリプレットだけでなく機能します

おすすめ

転載: blog.csdn.net/HeavenDan/article/details/115015624