动态规划小结 - 一维动态规划 - 时间复杂度 O(n),题 [LeetCode] Jump Game,Decode Ways
引言
一维动态规划根据转移方程,复杂度一般有两种情况。
func(i) 只和 func(i-1)有关,时间复杂度是O(n),这种情况下空间复杂度往往可以优化为O(1)
func(i) 和 func(1~i-1)有关,时间复杂度是O(n*n),这种情况下空间复杂度一般无法优化,依然为O(n)
本篇讨论第一种情况
例题 1
Jump Game
Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Determine if you are able to reach the last index.
For example:
A = [2,3,1,1,4], return true.
A = [3,2,1,0,4], return false.
class Solution {
public:
bool canJump(int A[], int n) {
}
};
这道题目肯定是用DP来做。
我一开始的想法为定义bool reachable[n] 数组,reachable[i] = true 表示第 i 元素可以到达末尾。
因此reachable[i] = if(reachable[i+1] == true || reachable[i+2] == true || ...|| reachable[i+A[i]] == true)
返回reachable[0]即为答案。
但是如果按这种思路写,需要用一个二维循环来完成整个过程,时间复杂度依然为O(n2)
按这种思路写出来的代码:
class Solution {
public:
bool canJump(int A[], int n) {
if(n <= ) return true;
bool *reachable = new bool[n-];
if(A[] >= (n-)) return true;
for(int i = n-; i >= ; --i){
if(A[i] >= (n--i)) reachable[i] = true;
else{
int j;
for(j = ; j <= A[i]; ++j){
if(reachable[i+j]){
reachable[i] = true;
break;
}
}
if(j > A[i]) reachable[i] = false;
}
}
return reachable[];
}
};
LeetCode上大数据是过不了的,超时。
网上参考了 http://blog.csdn.net/xiaozhuaixifu/article/details/13628465 的博文后,明白了上面这种思路的状态转移方程之所以效率低,是因为用bool 作为数组元素,这种思路本身就不是一个动态规划中推荐的思路。动态规划为了节省时间,往往尽可能地利用数组来存储最大量的信息,bool值只能存true和false。
改进版的思路是:这个数组不再单纯地存可达或不可达这样的bool值,而是存储从0位置出发的最大可达长度。定义数组int canStillWalk[n],canStillWalk[i]表示到达 i 位置后,依然有余力走出的最大长度。如果canStillWalk[i] < 0,表示走不到位置i。
状态转移方程为:
canStillWalk[i] = max(canStillWalk[i-1], A[i-1]) - 1;
这样我们在计算canStillWalk[i]时,就不再需要循环。
时间复杂度O(n), 空间复杂度 O(n)
class Solution {
public:
bool canJump(int A[], int n) {
if(n <= ) return true;
if(A[] >= (n-)) return true;
int *canStillWalk = new int[n];
canStillWalk[] = A[];
for(int i = ; i < n; ++i){
canStillWalk[i] = max(canStillWalk[i-], A[i-]) - ;
if(canStillWalk[i] < ) return false;
}
return canStillWalk[n-] >= ;
}
};
接着可以再简化,因为canStillWalk[i] 只和 canStillWalk[i-1]相关,那么我们就不需要定义一个数组来存放消息了,直接用pre和 cur就可以搞定,时间复杂度O(n), 空间复杂度 O(1):
class Solution {
public:
bool canJump(int A[], int n) {
if(n <= ) return true;
if(A[] >= (n-)) return true;
int pre = A[], cur = ;
for(int i = ; i < n; ++i){
cur = max(pre, A[i-]) - ;
if(cur < ) return false;
pre = cur;
}
return cur >= ;
}
};
小结
对于动态规划的题,状态转移方程比较重要,这道题的特殊性在于"步数连续",就是说,A[i] = s,表明从A[i] 可以走1~s步,而不是给定的几个不连续的值,这样我们可以通过定义最长可达距离这个转移方程来简化思想。
例题 2
Decode Ways
A message containing letters from A-Z is being encoded to numbers using the following mapping:
'A' -> 1
'B' -> 2
...
'Z' -> 26
Given an encoded message containing digits, determine the total number of ways to decode it.
For example,
Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12).
The number of ways decoding "12" is 2.
时间复杂度O(n), 空间复杂度 O(1) 解法
class Solution {
public:
int numDecodings(string s) {
if(s.empty()) return ;
int pre = -, cur = , tmp;
for(int i = ; i <= s.length(); ++i){
tmp = cur;
if(s[i-] == ''){
if(isCode(s, i-, i-)) cur = pre;
else return ;
}else if(isCode(s, i-, i-))
cur += pre;;
pre = tmp;
}
return cur;
}
private:
bool isCode(string &s, int i, int j){
if(i < ) return false;
if(s[i] >= '' || s[i] == '') return false;
if(s[i] == '' && s[j] >= '') return false;
return true;
}
};
动态规划小结 - 一维动态规划 - 时间复杂度 O(n),题 [LeetCode] Jump Game,Decode Ways的更多相关文章
- LeetCode总结 -- 一维动态规划篇
这篇文章的主题是动态规划, 主要介绍LeetCode中一维动态规划的题目, 列表如下: Climbing StairsDecode WaysUnique Binary Search TreesMaxi ...
- Leetcode 91. Decode Ways 解码方法(动态规划,字符串处理)
Leetcode 91. Decode Ways 解码方法(动态规划,字符串处理) 题目描述 一条报文包含字母A-Z,使用下面的字母-数字映射进行解码 'A' -> 1 'B' -> 2 ...
- 动态规划小结 - 二维动态规划 - 时间复杂度 O(n*n)的棋盘型,题 [LeetCode] Minimum Path Sum,Unique Paths II,Edit Distance
引言 二维动态规划中最常见的是棋盘型二维动态规划. 即 func(i, j) 往往只和 func(i-1, j-1), func(i-1, j) 以及 func(i, j-1) 有关 这种情况下,时间 ...
- 动态规划小结(dynamic programming)
动态规划在很多情况下可以降低代码的空间时间复杂度. 判断一道问题能否应用动态规划,需要关注问题是否具有最优子结构,当前规模的问题的解在之前问题的解里面,还要注意的是要满足无后效性的原则.随后就是寻找递 ...
- HDU 4502 吉哥系列故事——临时工计划(一维动态规划)
题意:吉哥的假期是1到n天,然后有m个工作可以让吉哥选择做,每个工作都有一个开始 t_s 和结束的时间 t_e ,都用天来表示,然后每个工作必须从第一天做到最后一天, 从头到尾做完之后就可以得到 ...
- leetcode 940. 不同的子序列 II (动态规划 ,字符串, hash,好题)
题目链接 https://leetcode-cn.com/problems/distinct-subsequences-ii/ 题意: 给定一个字符串,判断里面不相同的子串的总个数 思路: 非常巧妙的 ...
- 【2】【典型一维动态规划】【剑指offer+leetcode53】连续子数组的最大和
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决.但是,如果向量中包含负数 ...
- 每日一题 LeetCode 486. 预测赢家 【递推】【前缀和】【动态规划】
题目链接 https://leetcode-cn.com/problems/predict-the-winner/ 题目说明 题解 主要方法:递推:动态规划:前缀和 解释说明: 求前缀和 pre_nu ...
- 每日一题 LeetCode 491. 递增子序列 【递推】【递增子序列】【动态规划】
题目链接 https://leetcode-cn.com/problems/increasing-subsequences/ 题目说明 题解 主要方法:递推:动态规划 解释说明: 数据表示:观察数据范 ...
随机推荐
- ElasticSearch 2.0以后的改动导致旧的资料和书籍需要订正的部分
id原先是可以通过path指定字段的 "thread": { "_id" : { "path" : "thread_id" ...
- 基于AdaBoost算法——世纪晟结合Haar-like特征训练人脸检测识别
AdaBoost 算法是一种快速人脸检测算法,它将根据弱学习的反馈,适应性地调整假设的错误率,使在效率不降低的情况下,检测正确率得到了很大的提高. 系统在技术上的三个贡献: 1.用简单的Haa ...
- es6从零学习(五):Module的语法
es6从零学习(五):Module的语法 ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量 一:es6模块化和 CommonJS 和 AMD 模块 (运行 ...
- Python中的print
Python 3.X的print 在Python 3.X中,print是一个内置函数,完整的声明形式如下: print([object, ...][, sep=' '][, end='\n'][, f ...
- Java学习个人备忘录之关键字final
final关键字final可以修饰类,方法,变量.final修饰的类不可以被继承final修饰的方法不可以被覆盖final修饰的变量是一个常量.只能被赋值一次.内部类只能访问被final修饰的局部变量 ...
- Notes of the scrum meeting before publishing(12.19)
meeting time:18:30~20:30p.m.,December 19th,2013 meeting place:3号公寓一层 attendees: 顾育豪 ...
- QT界面绘制学习记录
1. MVC结构中,model必须作为类的成员变量存在,不可再函数内部申明.否则,会出现函数调用结束,model找不到的错误. 2.QcomboBox可设置为左边空白,右侧一小箭头的形式.代码:com ...
- 算法与数据结构实验题 6.4 Summary
★实验任务 可怜的 Bibi 丢了好几台手机以后,看谁都像是小偷,他已经在小本本上记 下了他认为的各个地点的小偷数量. 现在我们将 Bibi 的家附近的地形抽象成一棵有根树.每个地点都是树上的 一个节 ...
- "亿家App"问卷调查分析结果及心得体会
一.问卷问题设计 调查背景:随着现代社会互联网的发展,基于家庭产生的服务项目也越来越多.为增加家庭之间的交流和互助,增加家庭内部.家庭与家庭之间的沟通互助,并利用互联网便捷交流的优势,使家庭在享受服务 ...
- Qt自定义标题栏
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt自定义标题栏 本文地址:http://techieliang.com/2017/1 ...