[動的計画法問題 13] 最長の増加部分列 && スイング列

300. 最長の増加サブシーケンス

リンク: 300. 最長の増加サブシーケンス

1. ステータス表現*
dp[i] は、位置 i の要素で終わる「すべての部分列」の中で最も長く増加する部分列の長さを

2. 状態遷移方程式
dp[i] については、「部分列の構成方法」に基づいて分類の議論を行うことができます。

  1. i. サブシーケンスの長さは 1 です。現時点では dp[i] = 1 であり、自分でのみ再生できます。
  2. ii. サブシーケンスの長さが 1 より大きい場合: nums[i] は、前の任意の数値に続いてサブシーケンスを形成できます。前の数値の添字が j (0 <= j <= i - 1) であると仮定します。

nums[j] < nums[i] である限り、位置 i の要素が要素 j に続き、長さ
dp[j] + 1 の増加シーケンスを形成します。
したがって、要件を満たす最大の dp[j] + 1 を見つけるだけで済みます。
まとめると、dp[i] = max(dp[j] + 1, dp[i])、ここで 0 <= j <= i - 1 && nums[j]< nums[i]

3. 初期化
すべての要素は「個別に」増加する部分列を形成できるため、dp テーブル内のすべての要素を 1 に初期化できます。
4. フォームに記入する順番が
見やすく、「左から右」に記入する

5. 戻り値
最も長く増加する部分列が誰で終わるかわからないため、dp テーブルの「最大値」を返します。

コード:

 int lengthOfLIS(vector<int>& nums) {
    
    
      int n=nums.size();

        vector<int> dp(n,1);
        int Max=1;
        for(int i=1;i<n;i++)
        {
    
    
            for(int j=0;j<i;j++)
            {
    
    
                if(nums[i]>nums[j])
                dp[i]=max(dp[j]+1,dp[i]);
            }
            Max=max(Max,dp[i]);
        }
        return Max;
    }

ここに画像の説明を挿入します

376. スイングシーケンス

リンク: 376. スイングシーケンス

連続する数字の差が正の数字と負の数字の間で厳密に交互になる場合、その数字のシーケンスはウォブル シーケンスと呼ばれます。最初の違い (存在する場合) は、プラスまたはマイナスの場合があります。要素が 1 つだけ、または等しくない要素が 2 つあるシーケンスもウォブル シーケンスとみなされます。

たとえば、[1、7、4、9、2、5] は、差 (6、-3、5、-7、3) が正と負を交互に繰り返すため、振動シーケンスです。

反対に、[1, 4, 7, 2, 5] と [1, 7, 4, 5, 5] はスイング シーケンスではありません。最初のシーケンスは、最初の 2 つの差が両方とも正の数であるためです。2 番目のシーケンスは、最後の差はゼロです。
サブシーケンスは、元のシーケンスから一部の (またはそうでない) 要素を削除し、残りの要素を元の順序のままにすることによって取得できます。

整数配列 nums を指定すると、ウォブル シーケンスとして nums 単位で最長のサブシーケンスの長さを返します。

例 1:

入力: nums = [1,7,4,9,2,5]
出力: 6
説明: シーケンス全体はスイングシーケンスであり、各要素の差は (6, -3, 5, -7, 3) です。 。
例 2:

入力: nums = [1,17,5,10,13,15,10,5,16,8]
出力: 7
説明: このシーケンスには、長さ 7 のいくつかのウォブル シーケンスが含まれています。
そのうちの 1 つは [1, 17, 10, 13, 10, 16, 8] で、要素間の差は (16, -7, 3, -3, 6, -8) です。
例 3:

入力: nums = [1,2,3,4,5,6,7,8,9]
出力: 2

1. ステータス表示

  1. f[i] は、i 位置要素で終わるすべての部分列のうち、最後の位置が「上昇傾向」を示す最も長いスイング列の長さを意味します。
  2. g[i]は、i 位置要素で終わるすべての部分列のうち、最後の位置が「下降傾向」を示す最長のスイング列の長さを表します。

2.
状態遷移方程式の部分列の特殊な構成により、i 位置は終了部分列であり、前の位置は [0, i - 1] 内の任意の位置になる可能性があるため、j を [0, i - とします。 1] 区間内の特定の位置。
f[i] については、「部分列の形式」に基づいて分類の議論を行うことができます。

  1. i. サブシーケンスの長さは 1 です: 現時点では f[i] = 1 であるため、自分でのみ再生できます。
  2. ii. 部分列の長さが 1 より大きい場合: 末尾が上昇傾向を示す必要があるため、nums[j] < nums[i] を満たす必要があります。この条件では、j の末尾は下降傾向を示す必要があります。 . 最長のスイング シーケンスは g[j] + 1
    したがって、すべての条件を満たす最大の g[j] + 1 を見つける必要があります。

要約すると、f[i] = max(g[j] + 1, f[i])g[j] を使用する場合は判断が必要であることに注意してください。
g[i]も同様です。

3. 初期化
すべての要素は「個別に」スイングシーケンスを形成できるため、dp テーブル内のすべての要素を 1 に初期化できます。
4. フォームに記入する順番が
見やすく、「左から右」に記入する

5. 戻り値は
「2 つの dp テーブルの最大値」を返す必要があります。フォームに入力するときに「最大値」を更新できます。

コード:

 int n=nums.size();

        vector<int> f(n,1),g(n,1);
        int Max=1;
        for(int i=1;i<n;i++)
        {
    
    
            for(int j=0;j<i;j++)
            {
    
    
                if(nums[i]>nums[j])
                {
    
    
                    f[i]=max(f[i],g[j]+1);
                }
                if(nums[i]<nums[j])
                {
    
    
                    g[i]=max(f[j]+1,g[i]);
                }
                Max=max(Max,max(g[i],f[i]));
            }
        }
        return Max;

ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/m0_64579278/article/details/132797294