问题
看这里。
题解
看到这个题,应该很容易就想到动态规划啦!我们假设对一串长度为 n 的标准输入 s
能得到解码种数为 dp[n]
。根据题意,应该有以下关系成立:
- 如果
s[n-1]
不能够与s[n-2]
组合,dp[n] = dp[n - 1]; - 反之,dp[n] = dp[n - 1] + dp[n - 2]。
- 这里还有个小陷阱,对于能组合的
s[n-1]
与s[n-2]
来说,如果s[n-1]
为 0 的话,则 dp[n] = dp[n - 2];
举个栗子,对于输入 123
,求 dp[3]。
由于 2 能与 3 组合,所以产生的解码方式总数就为 dp[2](不组合)+ dp[1](组合)。
有了思路,代码就很简单啦!
代码
#include <stdio.h>
#include <string.h>
#define LIMIT 5000
long decode(const char str[]);
int main() {
char input[LIMIT];
while (scanf("%s", input) && input[0] != '0')
printf("%ld\n", decode(input));
return 0;
}
long decode(const char str[]) {
int len = strlen(str);
long dp[len];
int i;
dp[0] = 1;
for (i = 1; i < len; ++i)
if (str[i] == '0' && (str[i - 1] == '1' || str[i - 1] == '2'))
if (i > 1)
dp[i] = dp[i - 2];
else
dp[i] = 1;
else if (str[i - 1] == '1' || str[i - 1] == '2' && str[i] <= '6')
if (i > 1)
dp[i] = dp[i - 1] + dp[i - 2];
else
dp[i] = dp[i - 1] + 1;
else
dp[i] = dp[i - 1];
return dp[i-1];
}
很明显,这个解法的时间复杂度为 O(n),空间复杂度也为 O(n)。但仔细观察你会发现,这里只用到了 dp[i]
、dp[i-1]
、dp[i-2]
,多用的空间是完全没有必要的!所以,你可以这么写:
long decode_mini(const char str[]) {
long current, prev, pprev;
int i;
pprev = prev = current = 1;
for (i = 1; str[i] != '\0'; ++i) {
if (str[i] == '0')
current = pprev;
else if (str[i - 1] == '1' || str[i - 1] == '2' && str[i] <= '6')
current = prev + pprev;
else
current = prev;
pprev = prev;
prev = current;
}
return current;
}
今日阅读笔记
C语言 操作符优先级
注意:
1. ~ 和 ! 操作符比 & | ^ 优先级高多了(明明都是位操作符~)
2. && 优先级比 || 高
3. 赋值操作符优先级只比 ,
高
4. & | ^ 的优先级没有比较操作符(==,>=,<=)高