题意整理

  • 有一段长度为n的消息,要将消息分成若干组,每组2个消息。
  • 第一个消息长度必须是4,第二个消息长度不能为0。
  • 求有多少种分割方法。

方法一(递归)

1.解题思路

  • 递归终止条件:如果剩下的长度为0,说明正好完成分割,返回一种方案。
  • 递归如何推进:首先减去4,表示第一个消息的长度,然后第二个消息的长度可选1到rest之间的任意长度,统计所有的情况,作为当前层的方案数。
  • 每一层返回什么:返回当前层的方案数。

当数据比较大时,运行超时,如果进一步加大数据,会造成栈内存溢出(StackOverflowError)。

2.代码实现

import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 返回可以被压缩为长度为 N 的不同消息的数量
     * @param N int 数据包的总字节数
     * @return int
     */
    //取余常数
    int mod=998244353;
    public int messageCount (int N) {
        //递归
        return dfs(N);
    }

    private int dfs(int rest){
        //递归终止条件
        if(rest==0) return 1;
        //小于5不可压缩
        if(rest<5) return 0;
        //先选定第一个数字4,然后不断地尝试第二个数字
        rest-=4;
        int res=0;
        for(int i=1;i<=rest;i++){
            res=(res+dfs(rest-i))%mod;
        }
        return res;
    }
}

3.复杂度分析

  • 时间复杂度:每一层都有rest种选择,所以递归的次数为级别,所以时间复杂度为
  • 空间复杂度:需要额外深度为级别的递归栈,所以空间复杂度为

方法二(动态规划)

1.解题思路

我们可以将一组的两个消息绑在一起进行分析,问题转化为有多少种分组的方案。根据题目条件,一组至少分5个消息,至多分n个消息。所以当前长度(长度为n)消息的方案数,然后再分析长度为时的方案数,两式子相减,可得:,于是,可以根据这个递推关系,进行动态规划。

  • 状态定义:表示长度为i时,对应的消息压缩的方案数。
  • 状态初始化:当长度小于5时,不可压缩,直接赋为0。长度刚好为5时,只有一种方案,赋为1。
  • 状态转化:根据前面的分析,

动图展示:
图片说明

2.代码实现

import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 返回可以被压缩为长度为 N 的不同消息的数量
     * @param N int 数据包的总字节数
     * @return int
     */
    //取余常数
    int mod=998244353;
    public int messageCount (int N) {
        //不可压缩的情况
        if(N<5) return 0;
        //定义dp数组
        int[] dp=new int[N+1];
        //初始化
        dp[5]=1;
        for(int i=6;i<=N;i++){
            //状态转换
            dp[i]=(dp[i-1]+dp[i-5])%mod;
        }
        return dp[N];
    }
}

3.复杂度分析

  • 时间复杂度:假设消息长度为n,循环体需要执行次,所以时间复杂度为
  • 空间复杂度:需要额外长度为的空间,所以空间复杂度为