[ダイナミック プログラミング] [5.9 タスクを完了] 毎週のコンテストの問題をさらに 2 つ追加

動的プログラミング [完了] 5.9 タスク

Leetcode.53 最大部分配列と
Leetcode.120 三角形の最小パスと
Leetcode.63 異なるパス II
Leetcode.91 解読方法
Leetcode.198 強盗
Leetcode.300 最長増加部分列
Leetcode.72 編集距離
Leetcode.518 変更交換 II
Leetcode. 664 奇妙な PrinterLeetcode .10
正規表現
マッチリンク

1. Leetcode.53 の最大サブ配列合計

整数配列 nums が与えられた場合、最大合計を持つ連続部分配列 (部分配列には少なくとも 1 つの要素が含まれます) を見つけて、その最大合計を返します。

サブ配列は配列の連続した部分です。

  int maxSubArray(vector<int>& nums) {
        int ans=INT_MIN;
        int last=0;
        for(int i=0;i<nums.size();i++){
            int now=max(0,last)+nums[i];
            ans=max(ans,now);
            last=now;
        }
        return ans;
    }

2. Leetcode.120 三角形の最小パス合計

三角形の三角形が与えられた場合、上から下までの最小パス合計を見つけます。

各ステップは、次の行の隣接するノードにのみ移動できます。ここでの隣接ノードとは、添字が前の階層ノードの添字と同じか、前の階層ノードの添字 + 1 に等しい 2 つのノードを指します。つまり、現在の行のインデックス i にいる場合、次のステップは次の行のインデックス i または i + 1 に移動することになります。

  int minimumTotal(vector<vector<int>>& triangle) {
        vector<vector<long long>>dp(triangle.size(),vector<long long>(triangle.size()));
        dp[0][0]=triangle[0][0];
        for(int i=1;i<triangle.size();i++){
            for(int j=0;j<=i;j++){
                if(j>0&&i!=j){
                    dp[i][j]=min(dp[i-1][j],dp[i-1][j-1])+triangle[i][j];
                    cout<<dp[i][j]<<"="<<min(dp[i-1][j],dp[i-1][j-1])<<"+"<<triangle[i][j]<<" ";
                }
                else if(j==0){
                    dp[i][j]=dp[i-1][j]+triangle[i][j];
                    cout<<dp[i][j]<<' ';
                }else {
                    dp[i][j]=dp[i-1][j-1]+triangle[i][j];
                }
            }
            cout<<endl;
        }
        long long ans=INT_MAX;
        for(int i=0;i<triangle.size();i++)ans=min(ans,dp[triangle.size()-1][i]);
        return ans;
    }

3. Leetcode.63 の異なるパス II

ロボットは、mxn グリッドの左上隅に配置されます (下の図では、開始点は「開始」とマークされています)。

ロボットは一度に 1 ステップ下または右へのみ移動できます。ロボットはグリッドの右下隅 (下の画像では「終了」というラベルが付いている) に到達しようとします。

ここで、グリッド内に障害物があると考えてみましょう。では、左上隅から右下隅までの異なるパスは何通りあるでしょうか?

グリッド内の障害物と空いている位置はそれぞれ 1 と 0 で表されます。

  int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        if(obstacleGrid[0][0]==1)return 0;
        int m=obstacleGrid.size(),n=obstacleGrid[0].size();
        vector<vector<long long>>dp(m,vector<long long>(n));
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(obstacleGrid[i][j]==1)continue;
                if(i==0&&j!=0)dp[i][j]=dp[i][j-1];
                else if(i!=0&&j==0)dp[i][j]=dp[i-1][j];
                else if(i==0&&j==0)dp[i][j]=1;
                else{
                    dp[i][j]=dp[i-1][j]+dp[i][j-1];
                }
            }
        }
        return dp[m-1][n-1];
    }

4. Leetcode.91のデコード方法

エンコードされたメッセージをデコードするには、上記でマッピングされた方法に基づいて、すべての数字を文字にマッピングし直す必要があります (方法は複数ある場合があります)。たとえば、「11106」は次のようにマッピングできます。

「AAJF」、メッセージを (1 1 10 6) としてグループ化します。
「KJF」、メッセージを (11 10 6) としてグループ化します
。「06」は「」にマッピングできないため、メッセージを (1 11 06) としてグループ化できないことに注意してください。 F"。これは、「6」と「06」がマッピングにおいて等価ではないためです。

数値のみを含む空ではない文字列 s を指定した場合、デコード メソッドの合計数を数えて返します。

質問データは、回答が 32 ビット整数であることを保証します。

  int numDecodings(string s) {
        vector<int>dp(s.size());
        if(s[0]!='0')dp[0]=1;
        else return 0;
        if(s.size()>=2){
            if(s[1]-'0'>0)dp[1]++;
            if((s[0]-'0')*10+s[1]-'0'<=26&&(s[0]-'0')*10+s[1]-'0'>=10)
            dp[1]++;
        }
        for(int i=2;i<s.size();i++){
            if(s[i]!='0')dp[i]+=dp[i-1];
            if((s[i-1]-'0')*10+s[i]-'0'<=26&&(s[i-1]-'0')*10+s[i]-'0'>=10)dp[i]+=dp[i-2];
        }
        return dp[s.size()-1];
    }

5. Leetcode.198 は家や家を強盗します

あなたは通り沿いの家を盗むことを計画しているプロの泥棒です。各部屋には一定量の現金が隠されています。盗難に影響を与える唯一の制限要因は、隣接する家に相互接続された盗難防止システムが装備されていることです。同じ夜に隣接する 2 つの家が泥棒に侵入された場合、システムは停止します。自動的にアラームが鳴ります。

各家に保管されているお金の量を表す非負の整数の配列が与えられた場合、警報装置を作動させずに一晩に盗むことができる最大金額を計算します。

  int rob(vector<int>& nums) {
        int n=nums.size();
        vector<vector<int>>dp(n,vector<int>(2));
        dp[0][0]=0;
        dp[0][1]=nums[0];
        for(int i=1;i<n;i++){
            dp[i][0]=max(dp[i-1][1],dp[i-1][0]);//0不偷
            dp[i][1]=dp[i-1][0]+nums[i];
        }
        return max(dp[n-1][0],dp[n-1][1]);
    }

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

整数 num の配列が与えられた場合、その中で厳密に増加する最長のサブシーケンスの長さを見つけます。

サブシーケンスは、残りの要素の順序を変更せずに配列から要素を削除する (または削除しない) ことによって配列から導出されるシーケンスです。たとえば、[3,6,2,7] は配列 [0,3,1,6,2,2,7] のサブシーケンスです。

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

7. Leetcode.72 編集距離

word1 と word2 という 2 つの単語が与えられた場合、word1 を word2 に変換するために使用される演算の最小数を返してください。

  int minDistance(string word1, string word2) {
        word1=" "+word1;
        word2=" "+word2;
        int n1=word1.size();
        int n2=word2.size();
        vector<vector<int>>dp(n1,vector<int>(n2));
        for(int i=0;i<n1;i++)dp[i][0]=i;
        for(int i=0;i<n2;i++)dp[0][i]=i;
        for(int i=1;i<n1;i++){
            for(int j=1;j<n2;j++){
                dp[i][j]=min(dp[i][j-1],dp[i-1][j])+1;
                dp[i][j]=min(dp[i][j],dp[i-1][j-1]+(word1[i]!=word2[j]));
            }
        }
        return dp[n1-1][n2-1];
    }

8. Leetcode.518 チェンジエクスチェンジ II

さまざまな金種のコインを表す整数配列のコインと、合計金額を表す整数の金額が与えられます。

合計金額を構成できるコインの組み合わせの数を計算して返してください。合計金額に達しないコインの組み合わせがある場合は、0 が返されます。

各金種のコインが無限にあると仮定します。

質問データは、結果が 32 ビット符号付き整数に準拠していることを保証します。

  int change(int amount, vector<int>& coins) {
        vector<int>dp(amount+1);
        dp[0]=1;
        
        for(auto coin:coins)
            for(int i=coin;i<=amount;i++){
                dp[i]+=dp[i-coin];
        }
        return dp[amount];
    }

9. Leetcode.664 奇妙なプリンター

次の 2 つの特別な要件を持つ奇妙なプリンターがあります。

プリンターは毎回同じ文字のシーケンスのみを印刷できます。
新しい文字は毎回最初から最後まで任意の位置に印刷され、既存の文字は上書きされます。
文字列 s が与えられます。あなたのタスクは、このプリンタが印刷するために必要な最小印刷枚数を計算することです。

  int strangePrinter(string s) {
        if(s.empty())return 0;
        int n=s.size();
        vector<vector<int>>f(n+1,vector<int>(n+1));
        for(int len=1;len<=n;len++){
            for(int l=0;l+len-1<n;l++){
                int r=l+len-1;
                f[l][r]=f[l+1][r]+1;
                for(int k=l+1;k<=r;k++){
                    if(s[k]==s[l])
                        f[l][r]=min(f[l][r],f[l][k-1]+f[k+1][r]);
                }
            }
        }
        return f[0][n-1];
    }

10. Leetcode.10 正規表現マッチング

文字列 s と文字パターン p を指定した場合、「.」と「*」をサポートする正規表現マッチングを実装してください。

'.' は任意の 1 文字に一致します
'*' は前の要素の 0 個以上に一致します
いわゆる一致は、文字列の一部ではなく、文字列 s 全体をカバーします。

  bool isMatch(string s, string p) {
        int n = s.length(), m = p.length();
        vector<vector<bool>> f(n + 1, vector<bool>(m + 1, false));
        s = " " + s;
        p = " " + p;
        f[0][0] = true;
        for (int i = 0; i <= n; i++)
            for (int j = 1; j <= m; j++) {
                if (i > 0 && (s[i] == p[j] || p[j] == '.'))
                    f[i][j] = f[i][j] | f[i - 1][j - 1];
                if (p[j] == '*') {
                    if (j >= 2)
                        f[i][j] = f[i][j] | f[i][j - 2];
                    if (i > 0 && (s[i] == p[j - 1] || p[j - 1] == '.'))
                        f[i][j] = f[i][j] | f[i - 1][j];
                }
            }
        return f[n][m];
    }

おすすめ

転載: blog.csdn.net/Peanut31434331/article/details/124655565