[アルゴリズム叩き日記] day27——152.積の最大部分配列1567.積が正の最長部分配列の長さ

 152.積最大部分配列

152.積最大部分配列

トピックの説明:

整数配列を指定してください nums 。配列内で最大の積を持つ空でない連続部分配列を見つけて (部分配列には少なくとも 1 つの数値が含まれます)、その部分配列を返します。対応商品。

テスト ケースの答えは 32 ビット 整数です。

サブ配列 は、配列の連続したサブシーケンスです。

 問題解決のアイデア:

この質問は「部分配列の最大合計」と非常によく似ており、それに倣って状態表現と状態遷移を定義できます。
i. dp[i] 表⽰以 i 为结尾的所有⼦数组的最⼤乘积,
ii. dp[i] = max(nums[i], dp[i - 1] * nums[i]) ;
正負の符号が存在するため、簡単に求めることができるため、 dp[i] dp[i -
1] の情報では、 dp[i] 。たとえば、配列 [-2, 5, -2] では、上記の状態遷移を使用すると、 が得られます。
によって取得される dp 配列は [-2, 5, -2] であり、最大積は 5 。ただし、実際の最大積はすべての数値の乗算である必要があり、結果は になります。
果为 20
その理由は、 dp[2] を求めるとき、 nums [2] であるためです。 は負の数なので、必要なのは
i - 1 位置の最後にある最小の積 ( -10) )"、このようにして、負の数値に「最小値」を乗算すると実際の値が得られます
最大値。
したがって、「 dp 製品の最大値の表」だけでなく、「最小値の表」も必要になります。製品の値「 dp テーブル」。
1. 状态表⽰:
f[i] の意味: i
g[i] は、 i で終わるすべての部分配列の最小積を意味します。
2. 状態移行プロセス:
各位置を移動するときは、2 つの dp 配列の値を同時に更新する必要があります。
for f[i] 、つまり「 i
次の 3 つの形式があります。
i. ⼦数组的⻓度为 1 ,也就是 nums[i]
ii. ⼦数组的⻓度⼤于 1 ,但 nums[i] > 0 ,此时需要的是 i - 1 为结尾的所有⼦数组
的最⼤乘积 f[i - 1] ,再乘上 nums[i] ,也就是 nums[i] * f[i - 1]
iii. ⼦数组的⻓度⼤于 1 ,但 nums[i] < 0 ,此时需要的是 i - 1 为结尾的所有⼦数组
的最⼩乘积 g[i - 1] ,再乘上 nums[i] ,也就是 nums[i] * g[i - 1]
( nums[i] = 0 の場合、すべての部分配列の積は 0 、実際には 3 つの状況がすべて含まれます)
前述のとおり、 f[i] = max(nums[i], max(nums[i] * f[i - 1], nums[i] * g[i -
1]))。
for g[i] 、つまり「 i
次の 3 つの形式があります。
i. ⼦数组的⻓度为 1 ,也就是 nums[i]
ii. ⼦数组的⻓度⼤于 1 ,但 nums[i] > 0 ,此时需要的是 i - 1 为结尾的所有⼦数组
的最⼩乘积 g[i - 1] ,再乘上 nums[i] ,也就是 nums[i] * g[i - 1]
iii. ⼦数组的⻓度⼤于 1 ,但 nums[i] < 0 ,此时需要的是 i - 1 为结尾的所有⼦数组
的最⼤乘积 f[i - 1] ,再乘上 nums[i] ,也就是 nums[i] * f[i - 1]
综上所述, g[i] = min(nums[i], min(nums[i] * f[i - 1], nums[i] * g[i -
1]))
( nums[i] = 0 の場合、すべての部分配列の積は 0 、実際には 3 つの状況がすべて含まれます)
3. 初始化:
初期化を支援するために、先頭に補助ノードを追加できます。この手法を使用する場合、次の 2 つの点に注意してください。
i. 補助ノードの値は、後続のフォーム入力が正しいことを保証する必要があります。
ii. 添字のマッピング関係。
この質問では、先頭にグリッドを追加し、 f[0] = g[0] = 1 つまり Can とします。
4. 填表顺序:
状態転送プロセスによれば、フォームに記入する順序は「左から右へ、2 つのフォームを一緒に記入する」ことになります。
5. 返回值:
返回 f 表中的最⼤值。

解決策コード:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int n=nums.size();
        if(n==1)return nums[0];
        vector<int>f(n,0);
        vector<int>g(n,0);
        f[0]=nums[0];g[0]=nums[0];
        for(int i=1;i<n;i++)
        {
            f[i]=max(max(f[i-1]*nums[i],g[i-1]*nums[i]),nums[i]);
            g[i]=min(min(g[i-1]*nums[i],nums[i]*f[i-1]),nums[i]);
        }
        int ret=INT_MIN;
        for(int i=0;i<n;i++)ret=max(ret,f[i]);
        return ret;
        
    }
};

1567. 積が正の数になる最長の部分配列の長さ

1567. 積が正の数になる最長の部分配列の長さ

トピックの説明:

整数配列を指定してください nums 。その積が正の数になる最長の部分配列の長さを見つけてください。

配列の部分配列は、元の配列の 0 個以上の連続した数値で構成される配列です。

積が正の数になる最長の部分配列の長さを返してください。

 問題解決のアイデア:

アルゴリズムのアイデア:
引き続き「最大サブ配列合計」の状態表現に従って、この問題の解決を試みてください。
ステータスの意味: dp[i] は、「i で終わるすべての部分配列の中で最も長い部分配列で、その積が正の数である」ことを意味します。 「配列の長さ」。
思考状態の転送: nums[i] < で i a i= 4> については、次の 3 つの状況で議論できます。
i. If nums[i] = 0 、すべての < a i=4>i で終わる部分配列の積を正の数にすることはできません。この場合
dp[i] = 0 ;
ii. 如果 nums[i] > 0 ,那么直接找到 dp[i - 1] 的值(这⾥请再读⼀遍 dp[i -
1] は意味を表し、 dp[i - 1] の場合のノット値を考慮します。 0 の場合、効果は結果に影響しません)、 を追加します。
⼀即可,此时 dp[i] = dp[i - 1] + 1
iii. もし nums[i] < 0 なら、痛みがあるはずです。現在の状況では、 それを入手する方法はありませんからです。
の最大長。掛け算では「負のマイナスは正になる」ため、 dp[i - 1] に依存するだけでは を推定することはできません。
dp[i] 的值。
ただし、「 i - 1 で終わるすべての部分配列」がわかっている場合、その積が負の数である最も長い部分配列の長さは < /span>
度」 neg[i - 1] ,那么此时的 dp[i] 是不是就等于 neg[i - 1] + 1 呢?
上記の分析を通じて、最終結果を推定するには 2 つの dp テーブルが必要であると結論付けることができます。 「製品」だけが必要なわけではありません
「積が負の数になる最大の部分配列」と「積が負の数になる最大の部分配列」も必要です。
1. 状态表⽰:
f[i] の意味: i で終わるすべての部分配列のうち、積は長さ「正の数」の最も長い部分配列の
g[i] の意味: i で終わるすべての部分配列のうち、積は長さ「負の数」の最長の部分配列。
2. 状態移行プロセス:
各位置を移動するときは、2 つの dp 配列の値を同時に更新する必要があります。
対象 f[i] 、つまり i は、最終積が「正の数」である最大の部分配列です。 nums[i] の値に従って、
3 つの状況に分けて説明します。
i. nums[i] = 0 、すべて i < i=4> で終わる部分配列の積を正の数にすることはできません。この場合、 f[i] =
0
ii. nums[i] > 0 时,那么直接找到 f[i - 1] 的值(这⾥请再读⼀遍 f[i - 1] 代表
を検討し、 f[i - 1] のノット値が 0 0 であるかどうかを検討します。 a> 、効果は結果に影響しません)、1 つ追加します。
今回 f[i] = f[i - 1] + 1 ;
iii. nums[i] < 0 时,此时我们要看 g[i - 1] 的值(这⾥请再读⼀遍 g[i - 1]
テーブルの意味。負の値は正の値になるため、積が i - 1 で終わる最長の部分配列が負の数 であることがわかっている場合、
長さは、 g[i - 1] < の値に従って、 1 を追加するだけです/span> は 2 つの状況に分けられます:
1. g[i - 1] = 0 i - 1 で説明します。 a>i - 1 a> は、積が負の数で終わる最長の部分配列です。 <
なぜなら nums[i] < 0 、つまり i 最後に正の積を持つ最大の部分配列も存在しません。これ
f[i] = 0
2. g[i - 1] != 0 i - 1 < で説明します。 /span> は、積が負の数で終わる最大の部分配列です。 <
なぜなら nums[i] < 0 、つまり i 最後に正の積を持つ最長の部分配列は g[i - に等しい
1] + 1 ;
上で説明したように、 nums[i] f[i] = g[i - 1] == 0 ? 0 : g[i - 1] + のとき、 0
1;
for g[i] 、つまり i は、最終積が「負の数」である最大の部分配列です。 nums[i] の値に従って、
3 つの状況に分けて説明します。
i. nums[i] = 0 、すべて i < i=4> で終わる部分配列の積を負の数にすることはできません。この場合、 g[i] =
0
ii. nums[i] < 0 时,那么直接找到 f[i - 1] 的值(这⾥请再读⼀遍 f[i - 1] 代表
を検討し、 f[i - 1] のノット値が 0 0 であるかどうかを検討します。 a> 、効果は結果に影響しません)、
(正の数 * 負の数 = 負の数であるため)、このとき g[i] = f[i - 1] + 1 ;
iii. nums[i] > 0 时,此时我们要看 g[i - 1] 的值(这⾥请再读⼀遍 g[i - 1]
テーブルの意味。正の数 * 負の数 = 負の数) であるため、 g[i - 1] の値に応じて、次の 2 つの状況が存在します。
1. g[i - 1] = 0 i - 1 で説明します。 a>i - 1 a> は、積が負の数で終わる最長の部分配列です。 <
なぜなら nums[i] > 0 、つまり i 積が負の数で終わる最大の部分配列も存在しません。これ
f[i] = 0
2. g[i - 1] != 0 i - 1 < で説明します。 /span> は、積が負の数で終わる最大の部分配列です。 <
なぜなら nums[i] > 0 、つまり i 最後に正の積を持つ最長の部分配列は g[i - に等しい
1] + 1 ;
上で説明したように、 nums[i] > 0 のとき、 g[i] = g[i - 1] == 0 ? 0 : g[i - 1] +
1 ;
「正の数と負の数」については常に議論されるため、ここでの導出はかなり複雑ですが、以下のルールに厳密に従うだけで済みます。
この状態で必要な dp 配列を セルで見つけます。
i. 正の数 * 正の数 = 正の数
ii. 負の数 * 負の数 = 正の数
iii. 負の数 * 正の数 = 正の数 * 負の数 = 負の数
3. 初始化:
初期化を支援するために、先頭に「補助ノード」を追加できます。この手法を使用する場合、次の 2 つの点に注意してください。
i. 補助ノードの値は、「後続のフォーム入力が正しいことを保証する」必要があります。
ii. 「添字マッピング関係」。
この質問では、先頭にグリッドを追加し、 f[0] = g[0] = 0 つまり Can とします。
4. 填表顺序:
「状態伝達方程式」によれば、フォームに記入する順序は「左から右へ、2 つのフォームを一緒に記入する」です。
5. 返回值:
「ステータス表現」に従って、 f テーブルの最大値を返したいと考えています。

解決策コード:

class Solution {
public:
    int getMaxLen(vector<int>& nums) {
        int n=nums.size();
        vector<int>f(n+1,0);
        vector<int>g(n+1,0);
        int ret=INT_MIN;
        for(int i=1;i<=n;i++)
        {
            if(nums[i-1]>0)
            {
                f[i]=f[i-1]+1;
                g[i]=g[i-1]==0?0:g[i-1]+1;
            }
            else if(nums[i-1]<0)
            {
                g[i]=f[i-1]+1;
                f[i]=g[i-1]==0?0:g[i-1]+1;
            }
            ret=max(ret,f[i]);
        }
        return ret;
    }
};

おすすめ

転載: blog.csdn.net/m0_69061857/article/details/134339013