引言

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

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. leetcode个人题解——#15 3sums

    class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { sor ...

  2. 卸载CDH5.7

    CDH5.7卸载1.记录用户数据目录2.关闭所有服务2.1在CM中,选择某个集群,然后停止集群.2.2逐个关闭CDH中的服务3.删除parcels4.删除集群5.卸载Cloudera manager ...

  3. POJ 2177 Ghost Busters(三维几何)

    Description The famous Ghost Busters team has decided to upgrade their Ectomobile (aka Ecto-1) with ...

  4. POJ 1995 (快速幂)

    这道题普通做法会发生溢出且会超时,应当用快速幂来求解. 快速幂讲解 #include <cstdio> #include <cmath> using namespace std ...

  5. PHP 签到,与时间获取,数组长度获取

    本文实例讲述了php实现签到功能的方法.分享给大家供大家参考,具体如下:首先我在数据库里建了两张表,一个是用户的积分表,一个是签到状态表,分来用来记录用户的积分数和先到状态 在用户签到状态表中我们有一 ...

  6. 《JavaScript 高级程序设计》总结

    一.JS基本概念 1.命名规则 变量名区分大小写(test和Test是两个不同的变量名),标识符采用驼峰命名格式,即:第一个字母小写,剩下的每个有意义的单词首字母大写: 标识符第一个字符必须是以字母. ...

  7. javaIO--字符流

    java提供字符流对自否刘式文件进行数据读写操作.字符输入流类是Reader及其子类,输出流是Writer及其子类. 另外,上一篇javaIO写的是字节流,字节流方式也可以对以字符为基本类型的流式文件 ...

  8. ZOJ 1913 J-Eucild's Game

    https://vjudge.net/contest/67836#problem/J Two players, Stan and Ollie, play, starting with two natu ...

  9. 浅谈 Vue v-model指令的实现原理 - 如何利用v-model设计自定义的表单组件

    原文请点击此链接  链接1 http://www.7zhang.com/index/cms/read/id/234515.html  链接2 http://blog.csdn.net/yangbing ...

  10. Linux less命令语法

    一.Linux less命令语法 less [参数] 文件 less命令非常强大,在此只介绍几个常用的参数,更多参数使用man less来查看Linux帮助手册. -b <缓冲区大小> 设 ...