引言

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

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. halcon安装提示could not write updated path to HKLM

    halcon安装提示could not write updated path to HKLM 我们在安装Halcon软件时,会弹出如上图错误信息,这个错误信息提示软件无法写入本地注册表,造成这个原因有 ...

  2. 【转载】Android 内存溢出如何发生的。

    [转载]Android 内存溢出如何发生的. 且谈Android内存溢出 前言 关于android的内存溢出在创新文档库中也有不少,网络上也有很多这方面的资料.所以这遍文章不算是正真意义上的创新,仅仅 ...

  3. Python3 数值类型与运算符

    1.数值类型与进制 (1)基本类型 整型:int 浮点型:float 布尔类型:bool 复数:complex print(type(1)) print(type(1.1)) print(type(F ...

  4. var,let,const,三种申明变量的整理

    javascript,正在慢慢变成一个工业级语言,势力慢慢渗透ios,安卓,后台 首先let,是局部变量,块级作用域:var全局的,const是常量,也就是只读的: 一行demo说明 for (var ...

  5. 简单DP

      1.一只小蜜蜂   有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行.请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数. 其中,蜂房的结构如下所示. Input输入数据的第一行是一个整数N,表 ...

  6. Bus of Characters(栈和队列)

    In the Bus of Characters there are nn rows of seat, each having 22 seats. The width of both seats in ...

  7. 创建、编译、执行 java程序

    java源文件(.java)——Java字节码文件(.class)——在java虚拟机上执行 其他语言很多是编译后执行,所以无法跨平台

  8. k邻近算法理解及代码实现

    github:代码实现 本文算法均使用python3实现 1 KNN   KNN(k-nearest neighbor, k近邻法),故名思议,是根据最近的 $ k $ 个邻居来判断未知点属于哪个类别 ...

  9. 【week2】 词频统计效能分析

    效能统计工具:Jprofiler License Key:L-Larry_Lau@163.com#23874-hrwpdp1sh1wrn#0620 该性能分析工具对服务器进行监听,图一是线程变化图,当 ...

  10. C的强制转换和C++的强制转换(转)

    C的强制转换: (type)<expression> 其中,type为类型描述符,如int,float等.<expression>为表达式.经强制类型转换运算符运算后,返回一个 ...