Basics on Dynamic Programming(DP) 3 - Sequence DP
第2类常见DP问题:Sequence DP,一个序列,第i的状态只考虑前i个
1. Climbing Stairs - Leetcode 70
You are climbing a stair case. It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps.
In how many distinct ways can you climb to the top?
- state: f[i]代表”前”i层楼梯,走到了第i层楼梯的方案数
- function: f[i] = f[i - 1] + f[i - 2]
- intialize: f[0] = 1
- answer: f[n]
压缩空间:因为只前2个数有用,所以不需要n的数组
2. Decode Ways - Leetcode 91
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.
类似前一题,记录cur前2个的种类数,一直遍历到最后:
3. Jump Game - Leetcode 55
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.
下面这个递推式子不太好,时间复杂度高:
- state: f[i] 代表前i个格子,跳到了第i个格子,是否可行
- function: f[i] = OR(f[j], j < i && j可以跳到i)
- intialize: f[0] = true;
- answer: f[n-1]
贪心算法:O(n),但方法没有通用性
DP:
4. Jump Game II - Leetcode 45
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.
Your goal is to reach the last index in the minimum number of jumps.
For example:
Given array A = [2,3,1,1,4]
The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.)
- state: f[i]从第0个位置跳到”第i”个位置时,最少的跳跃次数(跳过了前i个位置)
- function: f[i] = min{f[j] + 1, j < i && j 能够跳到 i)
- intialize: f[0] = 0;
- answer: f[n-1];
DP超时:
另外方法:跳1步,能到的地方,类似滑动窗口:
5. Longest Increasing Subsequence - LIS 子序列
Given a sequence of integers, find the longest increasing subsequence (LIS).
You code should return the length of the LIS.
Example:
For [5, 4, 1, 2, 3], the LIS is [1, 2, 3], return 3
For [4, 2, 4, 5, 3, 7], the LIS is [4, 4, 5, 7], return 4
- state: f[i]表示[前i]个数字中,以[第i]个数为结尾的LIS最长是多少
- function: f[i] = max{f[i], f[j] + 1, j < i && nums[j] <= nums[i]}
- intialize: f[0..n-1] = 1, 变化
- answer: max(f[0..n-1]), 变化,所有的点都可能是终点。
另外,O(nlogn)的算法, 贪心 + 二分搜索:
注意:当出现1,5,8,2这种情况时,栈内最后的数是1,2,8不是正确的序列
分析一下,我们可以看出,虽然有些时候这样得不到正确的序列,但最后算出来的个数是没错的
当a[i]>top时,总个数直接加1,这肯定没错;但当a[i]<top时呢?这时a[i]会替换栈里面的某一个元素,大小不变,就是说一个小于栈顶的元素加入时,总个数不变。
这两种情况的分析可以看出,如果只求个数的话,这个算法比较高效;但如果要求打印出序列时,就只能用动态规划了。
若要求出序列,有另一种方法:用另外的数组记录前一个节点的位置