动态规划总结(二)

状态转移方程分类

对于动态规划类题目,当我们完成数据建模的之后,需要列出状态转移方程(事实上这两个步骤是相互关联的),通过总结leetcode上动态规划类题目的解法,一般来说状态转移方程分为以下两个大类:

  • 找到当前状态与之前某个状态之间的关系,通过之前状态的值求解当前状态的值
  • 找到当前状态与一些子状态之间的关联,通过遍历这些子状态求解当前状态的值

以上这两种情况在某些题目中可以相互转换的, 有些时候并不能直接找到历史某个状态与当前状态的关系,但可以遍历所有历史状态求解;有些题目很直观地看到是与所有历史的状态有关联,但通过对状态转移方程的化简,可以得到的推导式只与某个历史的状态相关。

状态转移方程实例

//思路:Strange Printer
//模型:dp[i][j]表示s.substr(i,j+1-i)需要多少次操作
//状态转移方程: dp[i][j] = min(dp[i][k] + dp[k+1][j] - s[j] == s[k]) k = i...j-1
//              当s[j] == s[j]的时候可以少进行一次操作
    int strangePrinter(string s) {
        if(s.empty() ) return 0;

        int n = s.size();

        vector<vector<int>> dp(n, vector<int>(n, n));
        for(int i = 0; i < n; i++) dp[i][i] = 1;

        for(int len = 1; len < n; len++) {
            for(int i = 0, j = i + len; j < n; i++,j++) {
                dp[i][j] = j + 1 - i;
                //遍历子状态去求解当前状态
                for(int k =  i + 1; k <= j; k++) {
                    int tmp = dp[i][k-1] + dp[k][j];
                    if (s[k-1] == s[j]) tmp--;
                    dp[i][j] = min(dp[i][j], tmp);
                }
            }
        }
        return dp[0][n-1];
    }
//思路:Palindromic Substrings
//模型:dp[i][j]表示s.substr(i, j+1-i)是否是回文串
//状态转移方程:dp[i][j] = dp[i+1][j-1] && s[i] == s[j] (注意边界条件)
//据说还有Manchester算法,可以将算法复杂度减少至O(n)
    int countSubstrings(string s) {
        if(s.empty()) return 0;
        int size = s.size();
        int res = 0;
        vector<vector<bool>> dp(size, vector<bool>(size, false));

        for(int i = 0; i < size; i++) dp[i][i] = true;

        for(int len = 1; len < size; len++) {
            for(int i = 0, j = i+len; j < size; ++i, ++j) {
                //当前状态只与dp[i+1][j-1]有关
                dp[i][j] = s[i]==s[j] && (i+1 >= j -1 || dp[i+1][j-1]);
                res += dp[i][j];

            }
        }

        return res + size;
    }

处理边界条件或者遍历的一些技巧

  • 对于用于动态规划的记忆数组/矩阵,可以适当增加一些边界状况下的值,这样不用单独挑出来考虑;
  • 遍历的方向dp[i][j]
  • 背包类问题
    • 针对物品是否能重复利用,dp[i][j]关于价值的j的递归方向是不一样的。

写在最后

这里总结了一些动态规划类题目常用的解法,然后希望通过参考这些解法,让我们在面临新的动态规划类的题目,有一些着角点进行尝试建模; 这是治标不治本的方式,不太符合学习规律;但这也是无奈之举,希望能帮助自己在较短的时间可以尝试做一些动态规划类的题目,以面对校招笔试面试中的各种面试题吧。

Node.js 开发微信公众号通常涉及到微信公众平台的API,其中涉及图片上传功能主要是通过调用微信提供的`素材管理`相关的接口。以下是基本步骤: 1. **配置微信开发者工具**:首先需要在微信公众平台上注册并创建一个公众号,然后在开发者中心完成服务器配置,获取AppID、AppSecret等必要信息。 2. **安装依赖库**:使用npm安装`wx-node-sdk`或者`wechaty`这样的第三方库,它们封装了微信API的操作,方便开发。 3. **初始化SDK**:导入所需的模块,设置access_token和token,这通常需要定期刷新以保持有效性。 ```javascript const wx = require('node-wx')({ appid: 'your_app_id', secret: 'your_app_secret', }); ``` 4. **上传图片**:调用`uploadMedia`方法,传入文件路径或者其他支持的媒体类型(如Base64编码的图片),请求返回media_id可以用于后续的消息发送。 ```javascript wx.uploadMedia({ localId: 'image.jpg', // 图片本地路径或Base64字符串 mediaType: 'image', // 图片类型 }, (err, res) => { if (err) console.error(err); else { const mediaId = res.mediaId; // 存储这个媒体ID以便后续使用 // 发送消息时附带图片 } }); ``` 5. **构建消息**:当准备发送包含图片的消息时,可以在消息结构体中加入`news_item`,其中包括图片链接(使用`media_id`生成的URL)。 6. **发送消息**:最后,通过`message.sendNews`等方法将构建好的图文消息发送给用户。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值