牛客竞赛每日俩题 - 动态规划1

目录

DP入门(存储之前状态以简化)

DP解决最短路问题


DP入门(存储之前状态以简化)

拆分词句_牛客题霸_牛客网

 思路:

方法:动态规划
状态:
        子状态:前1 2 3 ...,n 个字符能否根据词典中的词被成功分词
        F(i): 前 i 个字符能否根据词典中的词被成功分词
状态递推:
        F(i): true{j <i && F(j) && substr[j,i-j]能在词典中找到 } OR false
        在j 小于 i 中,只要能找到一个 F(j) true ,并且从 j+1 i 之间的字符能在词典
        中找到,则F(i) true
初始值:
        对于初始值无法确定的,可以引入一个不代表实际意义的空状态,作为状态的起始
        空状态的值需要保证状态递推可以正确且顺利的进行,到底取什么值可以通过简单
        的例子进行验证
        F(0) = true
返回结果: F(n)

例如题目样例:

当i==3时 有F[0]==true&&可找到[0,3]中有now,所以canbreak[3]==true;

当i==7时 有F[3]==true&&可找到[3,7]有code,所以canbreak[7]==true;

总结:利用F[i]存之前的状态是否可分割,然后搜索后面有无字符,两者都为true则这个整体可分割

class Solution {
public:
    bool wordBreak(string s, unordered_set<string> &dict) {
        if(s.empty()) return false;
        if(dict.empty()) return false;

        vector<bool> canbreak(s.size()+1,false);
        canbreak[0]=true;

        for(int i=1;i<=s.size();i++)
            for(int j=i-1;j>=0;j--){
                if(canbreak[j]&&dict.find(s.substr(j,i-j))!=dict.end()){
                    // F(i): true{j <i && F(j) && substr[j+1,i]能在词典中找到} OR false
                    canbreak[i]=true; 
                    break;
                }
                    
            }
            return canbreak[s.size()];
    }
};

DP解决最短路问题

三角形_牛客题霸_牛客网

状态:
        子状态:从(0,0) (1,0),(1,1),(2,0),...(n,n) 的最短路径和
        F(i,j): 从 (0,0) (i,j) 的最短路径和
状态递推:
        F(i,j) = min( F(i-1, j-1), F(i-1, j)) + triangle[i][j]
初始值:
        F(0,0) = triangle[0][0]
返回结果:
        min(F(n-1, i))

 方法一:递推法

利用dp算出所有路径,再找最短值

class Solution {
public:
    int minimumTotal(vector<vector<int> > &triangle) {
        if(triangle.empty()) return 0;

        vector<vector<int>> minsum(triangle);
        int line=triangle.size();

        for(int i=1;i<line;i++){
            for(int j=0;j<=i;j++){
                //处理左右边界
                if(j==0) minsum[i][j]=minsum[i-1][j]+triangle[i][j];
                else if(j==i) minsum[i][j]=minsum[i-1][j-1]+triangle[i][j];
                else{//核心操作
                    minsum[i][j]=min(minsum[i-1][j],minsum[i-1][j-1])+triangle[i][j];
                }
            }
        }
        int res=minsum[line-1][0];//找到最后一行的最短步数
        for(int i=1;i<line;i++) res=min(res,minsum[line-1][i]);
        return res;
    }
};

方法二:逆推法

状态:
子状态:
        从(n,n),(n,n-1),...(1,0),(1,1),(0,0) 到最后一行的最短路径和
        F(i,j): 从 (i,j)到最后一行的最短路径和
状态递推:
        F(i,j) = min( F(i+1, j), F(i+1, j+1)) + triangle[i][j]
初始值:
        F(n-1,0) = triangle[n-1][0], F(n-1,1) = triangle[n-1][1],..., F(n-1,n-1) = triangle[n-1] [n-1]
返回结果:
        F(0, 0)
class Solution {
public:
    int minimumTotal(vector<vector<int> > &triangle) {
        if(triangle.empty()) return 0;

        vector<vector<int>> minsum(triangle);
        int line=triangle.size();

        // 从倒数第二行开始
        for(int i=line-2;i>=0;i--)
        {
            for(int j=0;j<=i;j++){
                minsum[i][j]=min(minsum[i+1][j],minsum[i+1][j+1])+triangle[i][j];
            }
        }
        return minsum[0][0];
    }
};

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小黄同学LL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值