【动态规划】滚动数组的求解(C++)
虽然接触动态规划算法已经有一段时间,给一个01背包问题,能够做到一个表格简单粗暴下去,然后求得结果,但心里总觉得对这个算法理解十分不到位,抱着对算法的热爱,网上很多大牛的算法思维实在让我佩服的五体投地。在此讲一讲动态规划中滚动数组的求解方法,算是对这个知识点做一个记录,也希望有写的不妥的地方,大家能不吝赐教。
首先,我们先看看“滚动数组”的例题,大家可以参考http://www.lintcode.com/en/problem/house-robber/
题意大概就是说:一个盗贼要去偷盗一系列房子的财物,房子之间有报警器,当且仅当两个相邻的房子同时被偷盗的时候会自动报警,每个房子有一定的价值量,请问盗贼怎么做才能偷到最大价值的量。
求解这类题目要注意以下四点要素(也可以说是动态规划题目的四点要素):
1、状态(State)
用于存储小规模问题的结果
2、方程(Function)
由状态推出的一个方程,即怎么通过小的状态来推出大的状态
3、初始化(Initialization)
最初的状态,作为方程的起点
4、结果(Result)
根据每步的状态求出的结果
回到House-Robber这个题目,这个题目是个典型的滚动数组类型题。给定一个数组,我们不能够取相邻的两个元素,怎么取法可以使取得的结果和最大。比如给定[4,9,1],我们可以取[4,1]或者取[9],很明显一个结果是5,一个结果是9,所以我们这里的结果应该是后者的取法。在状态的确立上,我们可以这么理解,用A[n]数组表示每个元素(下标从0开始),当我们遇到第 i 个元素的时候,我们是取不取,当我们取了第i-1个元素的时候,我们就不能取了,要不就去掉第i-1个元素,以便于取得第i个元素。如果我们用f[n]来代表当遇到第n个元素,我们做出行动(取还是不取)之后,能够获得的最大值,那当取到第i个元素的时候,我们就是判断f[i-2] + A[i]和f[i-1]的大小,然后f[i] = max(f[i-2]+A[i],f[i-1]),你说是不是呢?我们无须去管i-3之前的元素是怎么取的,因为按照这个规律来,在f[i-2]已经包含了到i-2个元素位置能够取得的最大量了。
至此,以上已经阐明了这个思路的【状态】还有【方程】,剩下【初始化状态】和【结果】,我们可以注意到确定第i个方程的结果,往前需要用到i-2的元素,所以第0个元素和第1一个元素需要作为初始化的内容,因为这两个元素均不能用i-2的元素推倒出来,所以有f[0] = A[0],f[1] = max(A[1],A[0])。而结果就是我们对第n-1个元素做出行动之后的结果,该结果存储在f[n-1]当中。
通过代码实现:
long long houseRobber(vector<int> A){
if( == A.size()) return ;
int f[A.size()];
f[] = A[];
if(A.size()>) f[] = max(A[],A[]);
for(int i =;i<A.size();i++)
f[i] = A[i] + f[i-]> f[i-]? A[i] +f[i-]:f[i-];
return f[A.size()-];
}
这样,在时间复杂度O(n)可以求得结果,空间复杂度为O(n)。
【在这里我稍微拓展一下,f[i]的结果是通过对比f[i-2]+A[i]和f[i-1]的结果得来的,那其实i-3及其以前的空间都不需要再用到,所以我们可以只用三个空间重复使用来表示每一个状态,以达到空间复杂度为O(1)】
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
以上就是对一位数组的滚动数组算法求解过程,接下来探讨一下二维数组的滚动数组求解过程,大家可以参考http://www.lintcode.com/en/problem/maximal-square/
题意:给定一个只包含01的二维数组,求出最大的正方形,使这个正方形的所有元素都为1
我们用Matrix[n][m]表示这个二维数组,dp[n][m]表示左上角最大符合条件的正方形边长。首先,四个要素我们先来确定一下。【状态】我们要确定第[i,j]的状态要怎么确定呢,往前推一步有三个状态,分别是[i-1,j],[i,j-1]和[i-1,j-1],这三个状态同样表示了左上角最大的正方形,我们通过图来表示理解一下:

这里为了方便画出了dp[i-1][j],dp[i][j-1],dp[i-1][j-1]相等的情况,可以很容易看出,当dp[i-1][j],dp[i][j-1],dp[i-1][j-1]相等的时候dp[i][j]等于dp[i-1][j],dp[i][j-1],dp[i-1][j-1]其中的一个加上1,如果dp[i-1][j],dp[i][j-1],dp[i-1][j-1]不相等,那dp[i][j]取决于dp[i-1][j],dp[i][j-1],dp[i-1][j-1]之中小的那一个,这里偷懒就不画图了,大家可以自己动手画画看,嘿嘿~。因此【状态】确定了,【方程】也就容易得到dp[i][j] = min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1。【初始化状态】可以想到从[1,1]开始才能应用这个方程(假定我们是从[0,0]向[n,m]逐渐确定状态),所以i=0和j=0都是需要初始化的内容,这种情况下dp[i][j] = Matrix[i][j]。【结果】为dp矩阵中最大值的平方max{dp[n][m]}2。
代码实现:
int maxSquare(vector<vector<int> > &matrix) {
// write your code here
int row = matrix.size();
int col = matrix[].size();
int dp[row][col];
int _max = ;
for(int i =;i<row;i++){
dp[i][] = matrix[i][];
dp[i][col-] = matrix[i][col-];
_max = dp[i][]|dp[i][col-];
}
for(int i =;i<col;i++){
dp[][i] = matrix[][i];
dp[row-][i] = matrix[row-][i];
_max = dp[][i]|dp[row-][i];
}
for(int i =;i<row;i++)
for(int j = ;j<col;j++){
if( == matrix[i][j]) dp[i][j] = min3(dp[i-][j],dp[i][j-],dp[i-][j-]) +;
else dp[i][j] = matrix[i][j];
_max = max(dp[i][j],_max);
}
return _max*_max;
}
时间复杂度为O(n*m),空间复杂度为O(n*m)
【拓展:参考一位数组的拓展思路,我们确定[i,j]个状态,分别用到[i-1,j],[i,j-1],[i-1,j-1]这三个状态,所以我们可以想到可以用4个空间来重复表示各个状态,但由于对于二维数组,当换行的时候到了行首会丢失这个状态(因为4个空间在表示上一行末尾的四个状态了),所以我们只能用两行(2*n)个空间来维持这个状态】下面给出拓展后的代码,大家仅供参考,因为初始化状态被写在遍历过程中,可能会造成混乱,请谅解:
int maxSquare(vector<vector<int> > &matrix) {
int row = matrix.size();
int col = matrix[].size();
int dp[][col];
int _max = ;
for(int i =;i<col;i++) dp[][i] = matrix[][i];
for(int i =;i<row;i++)
for(int j=;j<col;j++){
if( == j ) dp[][j] = matrix[i][j];
else{
if( == matrix[i][j]) dp[][j] = min3(dp[][j],dp[][j-],dp[][j-])+;
else dp[][j] = ;
}
_max = max(_max,dp[][j]);
dp[][j-] = dp[][j-];
}
dp[][col-] = dp[][col-];
return _max*_max;
}
这样空间复杂度可以降到O(m)。
以上为个人对滚动数组的求解过程的理解,每一句代码均经过本人测试可用,如有问题,希望大家提出斧正。
尊重知识产权,转载引用请通知作者并注明出处!
【动态规划】滚动数组的求解(C++)的更多相关文章
- 2021.12.10 P2516 [HAOI2010]最长公共子序列(动态规划+滚动数组)
2021.12.10 P2516 [HAOI2010]最长公共子序列(动态规划+滚动数组) https://www.luogu.com.cn/problem/P2516 题意: 给定字符串 \(S\) ...
- 动态规划+滚动数组 -- POJ 1159 Palindrome
给一字符串,问最少加几个字符能够让它成为回文串. 比方 Ab3bd 最少须要两个字符能够成为回文串 dAb3bAd 思路: 动态规划 DP[i][j] 意味着从 i 到 j 这段字符变为回文串最少要几 ...
- POJ_1159 Palindrome (线性动态规划+滚动数组)
题意是说,给定一个字符串,问至少还需要插入多少个字符才能使得该字符串成为回文字符串. 这道题一开始做的时候用了一个简单的动态规划,开了一个5000*5000的数组,用递归形式实现,代码如下: 其中d[ ...
- HDU-1024 Max Sum Plus Plus 动态规划 滚动数组和转移优化
题目链接:https://cn.vjudge.net/problem/HDU-1024 题意 给n, m和一个序列,找m个不重叠子串,使这几个子串内元素和的和最大. n<=1e6 例:1 3 1 ...
- HDOJ-1024(动态规划+滚动数组)
Max Sum Plus Plus HDOJ-1024 动态转移方程:dp[i][j]=max(dp[i][j-1]+a[j],max(dp[i-1][k])+a[j]) (0<k<j) ...
- HDU-10240Max Sum Plus Plus+动态规划+滚动数组
Max Sum Plus Plus 题意:题意理解了老半天,这里是说在给定数列中,取m组子数列,不能有重复,使得这些子序列的和最大: 就比如m=2时候,1 /2/-4/5/6.可以不用拿-4的意思: ...
- nyoj--1184--为了肾六(动态规划+滚动数组)
为了肾六 时间限制:4000 ms | 内存限制:210535 KB 难度:2 描述 最近肾六很流行,goshawk看身边的朋友都用上了apple.自己还用着W年前的Samsung.于是决定去IT ...
- POJ-1038 Bugs Integrated, Inc. (状压+滚动数组+深搜 的动态规划)
本题的题眼很明显,N (1 <= N <= 150), M (1 <= M <= 10),摆明了是想让你用状态压缩dp. 整个思路如下:由于要填2*3或者3*2的芯片,那么就要 ...
- 动态规划(入门,滚动数组,记录的都是状态):SWUSTACM-1010 魔兽争霸之最后的反击
题目: 1010: 魔兽争霸之最后的反击 Time Li ...
随机推荐
- windows驱动之WDF---CharSample
驱动程序部分: NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ ...
- JDBC连接池(三)DBCP连接池
JDBC连接池(三)DBCP连接池 在前面的随笔中提到 了 1.JDBC自定义连接池 2. C3P0连接池 今天将介绍DBCP连接池 第一步要导入jar包 (注意:mysql和mysql 驱动 ...
- 芝麻HTTP:Python爬虫入门之正则表达式
1.了解正则表达式 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个"规则字符串",这个"规则字符串"用来 ...
- cookies、sessionStorage、和localStorage的区别。
为什么会有cookie和session? 我们都知道http是无状态的协议无连接的,客户每次在读取web页面时服务器都会打开新的会话.服务器不会自动维护客户上下文的信息,那么session就是一种保存 ...
- 畅通工程续 HDU - 1874
某省自从实行了很多年的畅通工程计划后,终于修建了很多路.不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多.这让行人很困扰. 现在 ...
- 手机浏览网页或打开App时莫名弹出支付宝领红包界面的原因及应对措施
自从支付宝推出扫码领红包活动后,这种模式独特的赏金机制,短时间内吸引了大量的关注,但是随之也产生了很多的问题,比由于如在赏金的驱动下,微信群里铺天盖地的红包口令,朋友圈里各式各样的领红包二维码图片, ...
- 创建文本节点createTextNode
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...
- [HNOI2013]切糕
题目描述 网址:https://daniu.luogu.org/problemnew/show/3227 大意: 平面上有一长方体,目标为将其切割为上下两半. 切割点为\((x,y,z)\)的点,每个 ...
- 【Webpack的使用指南 01】Webpack入门
使用Webpack有一段时间了,但是感觉之前学的用的都比较零散,所以在这里整理一下Webpack的使用知识,从入门到进阶. 创建项目 首先创建最简单的一个项目 npm init 得到以下项目结构: 安 ...
- 云计算之路-阿里云上:服务器CPU 100%问题是memcached的连接数限制引起的
非常抱歉,昨天的服务器CPU 100%问题是达到 memcached 的连接数限制引起的,不是阿里云服务器的问题. 之前我们用的是阿里云“云数据库 memcached 版”,上个周末我们换成了自己搭建 ...