引言

一维动态规划根据转移方程,复杂度一般有两种情况。

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的更多相关文章

  1. LeetCode总结 -- 一维动态规划篇

    这篇文章的主题是动态规划, 主要介绍LeetCode中一维动态规划的题目, 列表如下: Climbing StairsDecode WaysUnique Binary Search TreesMaxi ...

  2. Leetcode 91. Decode Ways 解码方法(动态规划,字符串处理)

    Leetcode 91. Decode Ways 解码方法(动态规划,字符串处理) 题目描述 一条报文包含字母A-Z,使用下面的字母-数字映射进行解码 'A' -> 1 'B' -> 2 ...

  3. 动态规划小结 - 二维动态规划 - 时间复杂度 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) 有关 这种情况下,时间 ...

  4. 动态规划小结(dynamic programming)

    动态规划在很多情况下可以降低代码的空间时间复杂度. 判断一道问题能否应用动态规划,需要关注问题是否具有最优子结构,当前规模的问题的解在之前问题的解里面,还要注意的是要满足无后效性的原则.随后就是寻找递 ...

  5. HDU 4502 吉哥系列故事——临时工计划(一维动态规划)

    题意:吉哥的假期是1到n天,然后有m个工作可以让吉哥选择做,每个工作都有一个开始 t_s  和结束的时间   t_e ,都用天来表示,然后每个工作必须从第一天做到最后一天, 从头到尾做完之后就可以得到 ...

  6. leetcode 940. 不同的子序列 II (动态规划 ,字符串, hash,好题)

    题目链接 https://leetcode-cn.com/problems/distinct-subsequences-ii/ 题意: 给定一个字符串,判断里面不相同的子串的总个数 思路: 非常巧妙的 ...

  7. 【2】【典型一维动态规划】【剑指offer+leetcode53】连续子数组的最大和

    HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决.但是,如果向量中包含负数 ...

  8. 每日一题 LeetCode 486. 预测赢家 【递推】【前缀和】【动态规划】

    题目链接 https://leetcode-cn.com/problems/predict-the-winner/ 题目说明 题解 主要方法:递推:动态规划:前缀和 解释说明: 求前缀和 pre_nu ...

  9. 每日一题 LeetCode 491. 递增子序列 【递推】【递增子序列】【动态规划】

    题目链接 https://leetcode-cn.com/problems/increasing-subsequences/ 题目说明 题解 主要方法:递推:动态规划 解释说明: 数据表示:观察数据范 ...

随机推荐

  1. 为什么请求时,需要使用URLEncode做encode转码操作(转)

    什么要对url进行encode 发现现在几乎所有的网站都对url中的汉字和特殊的字符,进行了urlencode操作,也就是: http://hi.baidu.com/%BE%B2%D0%C4%C0%C ...

  2. 《C++面试知识点》

    [动态内存] 1. 由内置指针管理的动态内存(即new和delete管理动态内存),直到被显式释放之前它都是存在的.假设该指针变量被销毁,那该内存将不会自动释放(即所谓的“内存泄漏”). 2. 可以用 ...

  3. MyBatis传入参数为list、数组、map写法(转载)

    MyBatis传入参数为list.数组.map写法 1.foreach简单介绍: foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach元素的属性主要有item ...

  4. Mac OS安装Scrapy失败

    报错: DEPRECATION: Uninstalling a distutils installed project (six) has been deprecated and will be re ...

  5. android入门 — PopupWindow

    第一步:自定义xml文件 第二步:获取LayoutInflater对象 第三步:调用inflate()方法获取View对象 第四步:创建PopupWindow对象 第五步:调用PopupWindow的 ...

  6. seaj和requirejs模块化的简单案例

    如今,webpack.gulp等构件工具流行,有人说seajs.requirejs等纯前端的模块化工具已经被淘汰了,我不这么认为,毕竟纯前端领域想要实现模块化就官方来讲,还是有一段路要走的.也因此纯前 ...

  7. 【Docker 命令】- run命令

    docker run :创建一个新的容器并运行一个命令 语法: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] OPTIONS说明: -a stdin: 指 ...

  8. Winform 数据绑定

    1.DataGridView数据绑定 namespace WindowsFormsApplication1 { public partial class Form1 : Form { private ...

  9. [STAThread] 作用

    [STAThread]是一种线程模型,用在程序的入口方法上(在C#和VB.NET里是Main()方法),来指定当前线程的ApartmentState 是STA. [STAThread]是声明开始线程用 ...

  10. Java中的多线程=你只要看这一篇就够了

    如果对什么是线程.什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内. 用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现.说这个话其 ...