博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
动态规划小结 - 一维动态规划 - 时间复杂度 O(n),题 [LeetCode] Jump Game,Decode Ways...
阅读量:5319 次
发布时间:2019-06-14

本文共 3896 字,大约阅读时间需要 12 分钟。

引言

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

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 <= 1) return true;        bool *reachable = new bool[n-1];        if(A[0] >= (n-1)) return true;        for(int i = n-2; i >= 0; --i){            if(A[i] >= (n-1-i)) reachable[i] = true;            else{                int j;                for(j = 1; j <= A[i]; ++j){                    if(reachable[i+j]){                        reachable[i] = true;                        break;                    }                }                if(j > A[i]) reachable[i] = false;            }        }        return reachable[0];    }};

 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 <= 1) return true;        if(A[0] >= (n-1)) return true;        int *canStillWalk = new int[n];        canStillWalk[0] = A[0];        for(int i = 1; i < n; ++i){            canStillWalk[i] = max(canStillWalk[i-1], A[i-1]) - 1;            if(canStillWalk[i] < 0) return false;        }        return canStillWalk[n-1] >= 0;    }};

 

接着可以再简化,因为canStillWalk[i] 只和 canStillWalk[i-1]相关,那么我们就不需要定义一个数组来存放消息了,直接用pre和 cur就可以搞定,时间复杂度O(n), 空间复杂度 O(1)

class Solution {public:    bool canJump(int A[], int n) {        if(n <= 1) return true;        if(A[0] >= (n-1)) return true;        int pre = A[0], cur = 0;        for(int i = 1; i < n; ++i){            cur = max(pre, A[i-1]) - 1;            if(cur < 0) return false;            pre = cur;        }        return cur >= 0;    }};

  

小结

对于动态规划的题,状态转移方程比较重要,这道题的特殊性在于"步数连续",就是说,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 0;        int pre = -1, cur = 1, tmp;        for(int i = 1; i <= s.length(); ++i){            tmp = cur;            if(s[i-1] == '0'){                if(isCode(s, i-2, i-1)) cur = pre;                else return 0;            }else if(isCode(s, i-2, i-1))                cur += pre;;            pre = tmp;        }        return cur;    }private:    bool isCode(string &s, int i, int j){        if(i < 0) return false;        if(s[i] >= '3' || s[i] == '0') return false;        if(s[i] == '2' && s[j] >= '7') return false;        return true;    }};

 

 

转载于:https://www.cnblogs.com/felixfang/p/3695579.html

你可能感兴趣的文章
css文本溢出显示省略号
查看>>
git安装和简单配置
查看>>
面向对象:反射,双下方法
查看>>
鼠标悬停提示文本消息最简单的做法
查看>>
课后作业-阅读任务-阅读提问-2
查看>>
面向对象设计中private,public,protected的访问控制原则及静态代码块的初始化顺序...
查看>>
fat32转ntfs ,Win7系统提示对于目标文件系统文件过大解决教程
查看>>
Awesome Adb——一份超全超详细的 ADB 用法大全
查看>>
shell cat 合并文件,合并数据库sql文件
查看>>
Android 将drawable下的图片转换成bitmap、Drawable
查看>>
介绍Win7 win8 上Java环境的配置
查看>>
移动、联通和电信,哪家的宽带好,看完你就知道该怎么选了!
查看>>
Linux设置环境变量的方法
查看>>
Atitit.进程管理常用api
查看>>
构建自己的项目管理方案
查看>>
利用pca分析fmri的生理噪声
查看>>
div水平居中且垂直居中
查看>>
epoll使用具体解释(精髓)
查看>>
AndroidArchitecture
查看>>
原生JavaScript第六篇
查看>>