算法练习(7) —— 动态规划 Strange Printer
2017-10-30 00:58
211 查看
算法练习(7) —— 动态规划 Strange Printer
动态规划
动态规划算法通常处理的是多阶段的决策最优化问题。挺多的问题都含有递推的思想。做这样的问题,最重要的就是找到对应的状态转移方程。也就是找到了对应的递推公式/递归公式,问题就可以迎刃而解。往往动态规划的实际代码并不算很复杂(至少我现在做到的是这样),但是要理解起来确实有点难度。习题
本次题目取自leetcode中的Dynamic Programming栏目中的第664题:
Strange Printer
题目如下:
Description:
There is a strange printer with the following two special requirements:
The printer can only print a sequence of the same character each time.
At each turn, the printer can print new characters starting from and ending at any places, and will cover the original existing characters.
Given a string consists of lower English letters only, your job is to count the minimum number of turns the printer needed in order to print it.
Examples:
Example 1:
Input: “aaabbb”
Output: 2
Explanation: Print “aaa” first and then print “bbb”.
Example 2:
Input: “aba”
Output: 2
Explanation: Print “aaa” first and then print “b” from the second place of the string, which will cover the existing character ‘a’.
Hint:
Length of the given string will not exceed 100.
思路与代码
首先理解一下题意:大概意思就是打印机每一次只能打印同一个字母,字母数不限。而且每一次起始打印位置不限,它可以在任意地方开始,并且覆盖原来的字母。让你求打印出要求字符所需的最少次数。可以按照给的例子分析一下:
第一个输入”aaabbb”可以由”aaaaaa”上面再打印3个”bbb”覆盖”aaa”达成。
那么首先可以想到的状态转移就是本次和上次的差别。但是由于2次字符串的差别有可能非常大,并不适合作状态转移方程的判断。
那么用字符串长度从1开始不断增加的递推呢?这是有可行性的,因为2个相邻的字母相同或者不同都有对应的关系。但是仔细想一下,反向使用递归可能更容易归纳公式和理解。
在这里采用的想法是:从目标串,不断的分出小子串去计算,以达到目的。那么用什么来作为分割的标准呢,比较容易想到的就是分割点的字母跟起点或者跟终点的字母相同。因为如果分割点跟终点的字母相同,可以理解为,分割点和终点之间在上一步都是一样的字母,下一步又被其他的字母染过去了(或者没被染)。分割点d,起点start,终点end。那么
dp[start][end] = dp[start][d] + dp[d + 1][end] - 1 (s[d] == s[end])
当然普通的情况也要考虑。这样的话状态转移方程就得到了,程序实现起来就容易啦~
这里用非递归方法来取代递归,代码如下:
#include <string> #include <algorithm> using namespace std; class Solution { public: int strangePrinter(string s) { int n = s.length(); if (n == 0) return 0; int dp[101][101]; memset(dp, 0, sizeof(dp)); for (int i = 0; i < n; i++) dp[i][i] = 1; for (int i = 1; i < n; i++) { for (int start = 0; start < n - i; start++) { int end = start + i; dp[start][end] = i + 1; for (int k = start; k < end; k++) { int sum = dp[start][k] + dp[k + 1][end]; if (s[k] == s[end]) sum--; dp[start][end] = dp[start][end] > sum ? sum : dp[start][end]; } } } return dp[0][n - 1]; } };
相关文章推荐
- 每周算法练习——用动态规划求解最短路径问题
- 算法练习 动态规划 装配线调度
- 算法练习 动态规划 硬币找零
- 每周算法练习——动态规划
- 算法练习笔记(十)——动态规划之回文子列的查找
- 算法练习笔记(十一)— 动态规划之分解问题
- poj 1458 小白算法练习 Common Subsequence 动态规划
- 最长公共子序列和回文字符串 动态规划 小白算法练习
- 算法练习---跳跃游戏二(动态规划)
- 算法练习(8) —— 动态规划
- 算法——动态规划练习
- 数据结构与算法练习-动态规划
- poj 1163-小白算法练习 The Triangle 动态规划
- 2018年全国多校算法寒假训练营练习比赛(第二场) B.TaoTao要吃鸡(动态规划)
- 算法导论——lec 11 动态规划及应用
- 动态规划——一个神奇的算法类
- 算法竞赛入门经典第二章练习
- 动态规划(5)字符串相似度算法
- ACM练习训练——零起点学算法76——绝对公正的裁判
- 机试算法讲解:第50题 动态规划之拦截导弹