题意
给定一个数字n,要求划分为x个 的数对,并且
方法一(暴力求解)
暴力枚举
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 返回可以被压缩为长度为 N 的不同消息的数量
* @param N int 数据包的总字节数
* @return int
*/
const int mod = 998244353;
int dfs (int rest) {
if (rest == 0) return 1; //搞定一个
if (rest < 5) { //不可能分为(4,x) (x>0)的数对
return 0;
}
rest -= 4;
int ret = 0;
for (int i = 1;i <= rest;++ i) {
ret += dfs (rest - i);
}
return ret;
}
int messageCount(int N) {
return dfs(N);
}
};因为层有rest种选择。所以时间复杂度为 ,空间复杂度也为
方法二(正解)
看到这个题目,我就想起高中时期学过的下楼梯计数问题。和这道题目非常类似。
这也是动态规划题目的一个共性,就是从小的状态推导更大的状态。只是状态转移方程不同。
我们研究一下状态是如何转移的。
考虑每次增加1,我们有两种方法。
一种是黏在上一个分组的最后一个数上。因为题目只要求数对的前一个数为4,对后一个数没有任何要求。
在完成这种方案的思考后,我们应该想想,还有哪种情况没有考虑到?因为题目要求数字不能为0,那么显然黏在上一组最后一个数后,我们新增加的数始终不能单独成组,也就是不能待在大小为1的线段内。所以我们可以单独为它创建一个组
根据乘法原理,
所以结合起来,得到公式
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 返回可以被压缩为长度为 N 的不同消息的数量
* @param N int 数据包的总字节数
* @return int
*/
const int mod = 998244353;
int messageCount(int N) {
int dp [1000001] = {0};
dp [5] = 1; //只有{4,1}一种分法
for (int i = 6;i <= N;++ i) {
// 第一种,可以直接跟在上一组最后一个数字后面 也就是总共的对数没有变化
// 第二种,自己单独组一个{4,1},因为数字不可能为零,所以若跟在上一组最后一个数字后面,是不可能单独为一组的。
dp [i] = (dp [i - 1] + dp [i - 5]) % mod;
}
return dp [N];
}
};因为保存了n个状态,所以空间复杂度为 ,而顺序递推的复杂度为

京公网安备 11010502036488号