1220.统计元音字母序列的数目-LeetCode

难度:困难

目录

一、问题描述

二、解题思想

1.方法一

2.方法二(动态规划)

三、解题

1、判断极端情况

2、代码实现


一、问题描述

这里我直接采用的LeetCode上面的问题描述。

给你一个整数 n,请你帮忙统计一下我们可以按下述规则形成多少个长度为 n 的字符串:

  • 字符串中的每个字符都应当是小写元音字母('a''e', 'i', 'o''u'
  • 每个元音 'a' 后面都只能跟着 'e'
  • 每个元音 'e' 后面只能跟着 'a' 或者是 'i'
  • 每个元音 'i' 后面 不能 再跟着另一个 'i'
  • 每个元音 'o' 后面只能跟着 'i' 或者是 'u'
  • 每个元音 'u' 后面只能跟着 'a'

由于答案可能会很大,所以请你返回 模 10^9 + 7 之后的结果。

下面给出示例:

二、解题思想

1.方法一

        首先我想到的是,根据题目的规定每个字母共有以下情况:

  • a 后面只能是e。
  • e 后面只能是a、i。
  • i 后面只能是a、e、o、u。
  • o 后面只能是i、u。
  • u 后面只能是a。

所以根据以上的情况:

  • 每有一个 a 结尾的字符串,就会产生一个 e 结尾的字符串。
  • 每有一个 e 结尾的字符串,就会分别产生一个 a 和 i 结尾的字符串。
  • 每有一个 i 结尾的字符串,就会分别产生一个以a、e、o、u结尾的字符串。
  • 每有一个 o 结尾的字符串,就会分别产生一个 i 和 u 结尾的字符串。
  • 每有一个 u 结尾的字符串,就会产生一个 a 结尾的字符串。

所以编写出了以下的代码:

int countVowelPermutation(int n) {
    const int mod = 1e10+7;
    //a、e、i、o、u结尾的字符串总个数的个数
    int a=1, e=1, i=1, o=1, u=1;
    for(int j = 2;j <= n; j++){
        //统计产生了多少个以a、e、i、o、u结尾的的字符串
        int tail_a=0,tail_e=0,tail_i=0,tail_o=0,tail_u=0;
        for(int m = 0;m < a ;m++){
            tail_e++;
        }
        for(int m = 0;m < e ;m++){
            tail_a++;tail_i++;
        }
        for(int m = 0;m < i ;m++){
            tail_a++;tail_e++;tail_o++;tail_u++;
        }
        for(int m = 0;m < o ;m++){
            tail_i++;tail_u++;
        }
        for(int m = 0;m < u ;m++){
            tail_a++;
        }
        a=tail_a;e=tail_e;i=tail_i;o=tail_o;u=tail_u;
    }
    return (a+e+i+o+u)%mod;
}

        上述解题思想的问题的是,求解 n 比较大的时候,就会超出时间,意思就是时间复杂度太高了,是指数级的时间复杂度。时间复杂度为O(n*a*e*i*o*u)

2.方法二(动态规划)

动态规划的思想是根据前面求解的解来求解后面的解。

        于是我换个方向,由往后推转变为往前推,来计算每个字母是由哪几个字母结尾的字符串生成的。可以得到以下规律:

  • a 是由以e、i、u结尾的字符串生成的。
  • e 是由以a、i结尾的字符串生成的。
  • i 是由以e、o结尾的字符串生成的。
  • o 是由以 i 结尾的字符串生成的。
  • u 是由以i、o结尾的字符串生成的。

通过以上的字符规则,我们可以得到动态规划递推公式如下:

  • dp[i][0]=dp[i-1][1]+dp[i-1][2]+dp[i-1][4]
  • dp[i][1]=dp[i-1][0]+dp[i-1][2]
  • dp[i][2]=dp[i-1][1]+dp[i-1][3]
  • dp[i][3]=dp[i-1][2]
  • dp[i][4]=dp[i-1][2]+dp[i-1][3]

        其中0、1、2、3、4分别表示 元音字母a、e、i、o、u、i,而 公式中的 i 则表示对应元音字母的个数。

        因为表示的是前一个状态的对应的个数,所以可以直接采用变量表示,不需要使用数组。因此,使用变量来表示每个字母结尾的字符串对应的前一个状态的个数和现在的个数即可。

三、解题

1、判断极端情况

        因为当n = 1时,只有五个元音字母所以这里我们 for循环开始要从 n= 2开始循环。

2、代码实现

int countVowelPermutation(int n) {
    const int mod = 1e9+7;
    //a、e、i、o、u结尾的字符串总个数的个数
    long int a=1, e=1, i=1, o=1, u=1;
    for(int j = 2; j<=n; j++){
        //能产生多少个以a、e、i、o、u结尾的字符串
        //换言之以a结尾的字符串是由 e、i、u结尾的字符串产生的 e、i、o、u也是同理
        long int Tail_a = (e+i+u)%mod;
        long int Tail_e = (a+i)%mod;
        long int Tail_i = (e+o)%mod;
        long int Tail_o = (i)%mod;
        long int Tail_u = (i+o)%mod;
        a = Tail_a;
        e = Tail_e;
        i = Tail_i;
        o = Tail_o;
        u = Tail_u;
    }
    return (a+e+i+o+u)%mod;
}

         以上就是对于本题,我查看资料以及自己思考所编写出来得题解,如果有更好的方法,欢迎大家在下方留言,一起讨论。👇👇

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Alkaid_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值