leetcode hot100 多维动态规划

如有缺漏谬误,还请批评指正。

1.不同路径

两种转移方式:从上到下/从左到右。

下标从1开始,f[1][1]初始化为1,循环里需特判跳过f[1][1]的计算。

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> f(m+1,vector<int>(n+1));
        f[1][1]=1;
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                if(i==1&&j==1) continue;
                f[i][j]=(f[i-1][j]+f[i][j-1]);
            }
        }
        return f[m][n];
    }
};

2.最小路径和

求最小值,状态转移数组需初始化为一个较大值。

(1)下标从0开始

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int m=grid.size();
        int n=grid[0].size();
        vector<vector<int>> f(m,vector<int>(n,500000));
        f[0][0]=grid[0][0];
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(i==0&&j==0) continue;
                if(i&&j) f[i][j]=min(f[i-1][j],f[i][j-1])+grid[i][j];
                else if(i) f[i][j]=f[i-1][j]+grid[i][j];
                else if(j) f[i][j]=f[i][j-1]+grid[i][j];
            }
        }
        return f[m-1][n-1];
    }
};

(2)下标从1开始

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int m=grid.size();
        int n=grid[0].size();
        vector<vector<int>> f(m+1,vector<int>(n+1,500000));
        f[1][1]=grid[0][0];
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                if(i==1&&j==1) continue;
                if(i&&j) f[i][j]=min(f[i-1][j],f[i][j-1])+grid[i-1][j-1];
                else if(i) f[i][j]=f[i-1][j]+grid[i-1][j-1];
                else if(j) f[i][j]=f[i][j-1]+grid[i-1][j-1];
            }
        }
        return f[m][n];
    }
};

3.最长回文子串

下标i遍历左边界,下标j遍历右边界,如果左右边界字符相同,当前最大回文子串长度+1。

class Solution {
public:
    string longestPalindrome(string s) {
        int n=s.size();
        if(n<2) return s;
        int maxv=1,st=0;
        vector<vector<bool>> f(n,vector<bool>(n,false));
        for(int i=0;i<n;i++) f[i][i]=true;  //所有长度为1的子串都是回文串
        //枚举子串长度
        for(int len=2;len<=n;len++){  
            //枚举子串左边界
            for(int i=0;i<=n-len;i++){
                int j=i+len-1;  //子串右边界
                if(s[i]==s[j]&&(len==2||f[i+1][j-1])){
                    f[i][j]=true;  //s[i...j]是回文串
                    if(len>maxv){
                        maxv=len;  //更新最大回文子串长度
                        st=i;  //更新最大回文子串起始位置
                    }
                }
            }
        }
        return s.substr(st,maxv);
    }
};

4.最长公共子序列

f[i][j]表示到A[i]和B[j]为止的最长公共子序列长度。

状态转移依据“当前字符是否一致”:

  • 一致:最长公共子序列长度+1
  • 不一致:f[i][j]=max(f[i-1][j],f[i][j-1]); 取两者间最大值。 
class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        int n=text1.size(),m=text2.size();
        vector<vector<int>> f(n+1,vector<int>(m+1,0));
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(text1[i-1]==text2[j-1]) f[i][j]=f[i-1][j-1]+1;
                else f[i][j]=max(f[i-1][j],f[i][j-1]); 
            }
        }
        return f[n][m];
    }
};

5.编辑距离

f[i][j] 表示将字符串 A[0..i-1] 转换成 B[0..j-1] 所需的最少操作次数。

三种编辑方式:增、删、改。

  • 增:f[i][j-1]+1  (在A的末尾插入B[j-1])
  • 删:f[i-1][j]+1  (删除A[i-1])
  • 改:f[i-1][j-1]+1  (替换A[i-1]为B[j-1])
class Solution {
public:
    int minDistance(string word1, string word2) {
        int m=word1.size();
        int n=word2.size();
        vector<vector<int>> f(m+1,vector<int>(n+1,INT_MAX));
        for(int i=0;i<=m;i++) f[i][0]=i;
        for(int j=0;j<=n;j++) f[0][j]=j;
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                if(word1[i-1]==word2[j-1]) f[i][j]=f[i-1][j-1];
                else{
                    f[i][j]=min(f[i-1][j],f[i][j-1])+1;
                    f[i][j]=min(f[i][j],f[i-1][j-1]+1);
                }
            }
        }
        return f[m][n];
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值