【コードランダム記録】ブラッシング問題 Day51&Day52

 51日目

1. 株の売買に最適な時期には凍結期間が含まれる

309. 株式の売買に最適な時期には凍結期間が含まれる

1. dp 配列の意味: dp[i][0] は i 日目に売却された株式の最大値、dp[i][1] は i 日目に保有された株式の最大値です。 2日目

2. dp アレイの状態: 凍結期間により、dp アレイの状態が変化しました。i 日目に売られた株式の最大値は、前回売られた株式の最大値と、前回売られた株式の最大値の 2 つの状況があるため、条件は次のようになります。 dp[i][0]= max(dp[i-1][0],dp[i-1][1]+価格[i])。また、i 日目に保有する株式の最高価額には、前回保有した株式の最高価額と、2 日前に売却した株式の最高価額の 2 種類があります(前回の保有株数は凍結期間中は販売できません)の場合、条件は dp[i][1]=max(dp[i-1][1],dp[i-2][0]-prices[i]); となります。

3. 初期化: dp[0][0]=0 および dp[0][1]=-prices[0] には何も言うことはありません。ただし、株式保有ロジックは i-2 になるため、つまり 1 からの移動で範囲外アクセスが発生する場合は、位置 1 の値を事前に設定する必要があります。位置 1 のロジックは必要ありません。フリーズ期間を考慮するため、続行します。 前の質問で dp 配列の条件を理解していれば、初期化が次のようになっていることが自然にわかります。 dp[1][0]=max(dp[0][0],dp[0][1] ]+価格[1]) および dp[1] ][1]=max(dp[0][1],dp[0][0]-価格[1]);

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.size()==1)
            return 0;
        vector<vector<int>>dp(prices.size(),{0,0});
        dp[0][0]=0;
        dp[0][1]=-prices[0];
        dp[1][0]=max(dp[0][0],dp[0][1]+prices[1]);
        dp[1][1]=max(dp[0][1],dp[0][0]-prices[1]);
        for(int i=2;i<prices.size();i++)
        {
            dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
            dp[i][1]=max(dp[i-1][1],dp[i-2][0]-prices[i]);
        }
        return dp[prices.size()-1][0];
    }
};

2. 株式の売買に最適なタイミングには手数料が含まれます

714. 株式の売買に最適な時期には手数料が含まれます

122. 株式の売買に最適な時期 II似ています

ためらい この質問にはいわゆる「手数料」が加算されており、実際には株式を売却する際には手数料を差し引くことが条件となっているのですが、端的に言えば元の売却額を基準にするともう少し安くなるのですが、最大値は dp 配列の意味によって異なります。配列の意味は依然として最大値ですが、頻繁に取引される可能性があり、元々頻繁に取引されていたストックメソッドの方が小さい可能性がありますが、dp配列は依然として手数料を差し引いた包含を取得する最も価値のある方法です。各購入と販売の場合、条件は当然手数料を差し引くだけでよいため、 dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices ) となります。 [i] -手数料)

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        vector<vector<int>>dp(prices.size(),{0,0});
        dp[0][0]=0;
        dp[0][1]=-prices[0];
        for(int i=1;i<prices.size();i++)
        {
            dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]-fee);
            dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);
        }
        return dp[prices.size()-1][0];
    }
};

3. まとめ

在庫問題の核心は、d 配列が何を表すかを決定することであり、すべての状況を含めるためにこのように定義する必要があると思います。

1. たとえば、初期在庫問題は最大値を見つけるだけであり、累積の問題を考慮する必要はなく、比較のために最大値を直接取得します。

2. たとえば、後ろの累積最大値は、実際には、前回の値と現在販売された在庫値を加算して最大値を見つけます。これは、最初の最大値よりも 1 段階多くの処理ロジックです。

3. 購入数にも制限があるため、設定した dp 配列は n 番目の株式保有または売却の定義を表す必要があります。最後に上下関係に基づいて条件判断を行う

したがって、実際には、最初にトピックの条件を明確にし、複数回購入するか 1 回購入するかに応じて、適切な dp 配列定義を見つける必要があります。次に、与えられた条件を見て、dp 配列の条件をシミュレートします。実際、シミュレーションの考え方は非常に単純です。単一の条件については、前回と現在の時間の関係を調べます。全体については、前回の時刻と現在の時刻の関係を調べます。 、各層の関係を見ることです。条件が決定されると、その条件に応じて対応する初期化が実行されます。初期化の初期値は、トピックの説明、dp の定義、dp 配列の対応する動作仕様を満たしている必要があり、最後に特別な初期化が必要かどうかを確認する必要があります。

52日目

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

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

1. 各数値の長さは 1 であるため、初期化は非常に簡単で、すべてが直接 1 に設定されます。

2. dp 配列の意味: i 番目の位置に対応する数値の最も長く増加する部分列

3. 条件: i 番目の位置では、前方を見て、前の各数値をたどる必要があります。j 位置の数値が i 位置より小さい場合、実際に更新を検討できます。更新は最長のものを見つけることです。次に、現在の長さを前の j 番目の位置 + 1 の長さと比較する必要があります。自然条件は dp[i]=max(dp[i],dp[j]+) です。 1)

4. dp 配列には、全体で最も長い数値ではなく、i に対応する最も長く増加する数値の部分列が格納されているため、ret で最長の数値を記録し、最後に戻り値を返す必要があります。

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        vector<int>dp(nums.size(),1);
        int ret = 1;
        for(int i=1;i<nums.size();i++)
        {
            for(int j=i-1;j>=0;j--)
            {
                if(nums[i]>nums[j])
                {
                    dp[i]=max(dp[i],dp[j]+1);
                }
            }
            ret=max(ret,dp[i]);
        }
        return ret;
    }
};

2. 最長連続増加シーケンス

674. 最長連続増加シーケンス

この問題は実際に現在位置の数値と一つ前の位置に対応する数値を比較しているのですが、前回の dp 更新よりも大きければ dp[i]=dp[i-1]+1 が比較的簡単なので勝ちです。詳細には触れないでください

class Solution {
public:
    int findLengthOfLCIS(vector<int>& nums) {
        vector<int>dp(nums.size(),1);
        int ret = 1;
        for(int i=1;i<nums.size();i++)
        {
            if(nums[i]>nums[i-1])
                dp[i]=dp[i-1]+1;
            ret=max(ret,dp[i]);
        }
        return ret;
    }
};

3. 最長反復部分配列

718. 最長反復サブ配列

1. dp 配列の意味: dp[i][j] は、i-1 と j-1 が比較される位置で繰り返される最大の部分文字列です。

2. 上記の意味から、条件比較はnums1[i-1]とnums2[j-1]の数値が同じかどうかであることがわかり、同じであれば、その時点での長さが一致することを意味します。 i-1 と j- の間の最後の比較です。1 より前の 2 つの数値の最も長く繰り返される部分配列の場合に 1 を加算します。つまり、dp[i][j]=dp[i-1][j- 1]+1;

3. dp 配列が i-1 と j-1 の状況として定義されている理由は、初期化で dp[i][0] と dp[0][j] に対応する数値が 0 である必要があるためです。実際に対応する番号が一致しないためです。i 位置と j 位置として定義すると、2 つの配列がそれぞれ初期化のために数値を取るすべてのケースを調べる必要があり、この定義のコストが高すぎます。

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        int ret = 0;
        vector<vector<int>>dp(nums1.size()+1,vector<int>(nums2.size()+1,0));
        for(int i=1;i<=nums1.size();i++)
        {
            for(int j=1;j<=nums2.size();j++)
            {
                if(nums1[i-1]==nums2[j-1])
                {
                    dp[i][j]=dp[i-1][j-1]+1;
                }
                ret=max(ret,dp[i][j]);
            }
        }
        return ret;
    }
};

おすすめ

転載: blog.csdn.net/m0_63488627/article/details/131102945