描述
A message containing letters from A-Z is being encoded to numbers using the following mapping:
‘A’ -> 1
‘B’ -> 2
…
‘Z’ -> 26
Given a non-empty string containing only digits, determine the total number of ways to decode it.
Example 1:
Input: “12”
Output: 2
Explanation: It could be decoded as “AB” (1 2) or “L” (12).
Example 2:
Input: “226”
Output: 3
Explanation: It could be decoded as “BZ” (2 26), “VF” (22 6), or “BBF” (2 2 6).
解析
因为爬梯子问题,每一步只能爬一步或者两步的情况,这道题目也是,decoding只能解码两个或者一个字母,而且是相邻的两种情况下,与爬梯子问题相比,加多了两个判断条件
属于动态规划,爬梯子问题变更版本,f(n ) = f(n-1) + f(n-2) 版本点问题
主要在两个点处,
判断两种条件
动态规划问题
主要有两个点(递进判断点关系)
(1)判断s[i ]是否为0,如果不等于0 则,s[i] =s[i-1], 是基础点,如果等于0 则
(2) 再判断s[i-1]s[i] 两个数是否在10和26之间,
复杂度
空间复杂度为O(N),时间复杂度为O(N),
private int dp(String s) {
int n = s.length();
int[] fn = new int[n+1];
fn[0] = 1;
fn[1] = s.charAt(0) != '0' ? 1 : 0;
//(i+1)代表在处理的数据
for (int i = 1; i < n; i++) {
if (s.charAt(i) != '0')
fn[i+1] = fn[i]; (最基础情况,不为0的话)
int v = Integer.parseInt(s.substring(i-1, i+1));
if (v >= 10 && v <= 26)
fn[i+1] += fn[i-1];
}
return fn[n];
}
改动代码体
class Solution {
public int numDecodings(String s) {
int n = s.length();
int[] dp = new int[n+1];
dp[0] = 1;
dp[1] = s.charAt(0) != '0' ? 1 : 0;
//i代表处理的字符串, i+1代表数组对应的数组下标,两者对应关系要搞好,
//要确定是从数组下标开始,还是从字符串位置开始
for(int i=2;i<=n;i++){
//i是带处理带字符串
if(s.charAt(i-1)!='0' )
dp[i] = dp[i-1];
//取得自负 (i-2,i-1,i);
int v = Integer.parseInt(s.substring(i-2,i));
if(v>=10 && v<=26)
dp[i] += dp[i-2];
}
return dp[n];
}
}
优化空间复杂度
最基础的情况
比如 1234和12345
1234有如下的情况
---------- 1,2,3,4
-----------12,3,4
-----------1,23,4
当加入 5 时,首先判读哪5不等于0 ,所以肯定有如下情况成立(把5单独作为一个选项)
基础dp[5] 最基础的有如下情况
-----------1,2,3,4,5
-----------12,3,4,5
-----------1,23,4,5
至于 还有没有多余的情况,就要看 s[i]和s[i-1], i代表正在成立的节点
查看其组成的数字是否满足
-------10到26之间的数据
如果是等于0的情况下,
---------1,2,3,4,0
----------12, 3, 4, 0
----------1, 23, 4, 0
上述三种情况均为不满足题意的,所有当s[i]=='0’时,dp[i] =0(基础)
接下来再判断 :40 ,因为 40不满足在 10 和20之间,所以 dp[i] = 0(最终情况)
如果把4 改成 1或者2, 则满足, dp[i] = dp[i-2]
如果满足上述两个条件则 套用 f(n) = f(n-1) + f(n-2), 怎样划分