力扣(LeetCode)940. 不同的子序列 II(C语言)

一、环境说明

  1. 本文是 LeetCode 940题 : 不同的子序列 II,使用c语言实现
  2. 模拟动态规划
  3. 测试环境:Visual Studio 2019

二、代码展示

const int mod = 1e9 + 7;

int distinctSubseqII(char * s) {
    int g[26]={0};//26个小写字母
    int total = 0,i = 0;//初始为0
    while(*(s+i)){//遍历一遍s
        int ch = s[i] - 'a';//当前字符对应g的位置
        int pre = g[ch];//上一个相同字符的组合数量
        g[ch] = (total + 1) % mod;//以当前字符结尾的组合数量
        total = ((total + g[ch] - pre) % mod + mod) % mod;//总数要二次取余,组合数太大,一次取余依然超出INT_MAX
        i++;//看s的下一个字符
    }
    return total;
}

三、思路分析

  • 本题的字符串s只包含26个小写字母的,最大长度2000,求它的子序列数量。
  • 对于组合数,有一些数学性质需要分析。
  • 性质①,对于一个字符串,比如ab,在其后插入一个字符c,变成abc。以c结尾的组合数,和原字符串ab的组合数有关。
  • 具体关系如下:ab可能的组合有 a、b、ab,一共3个组合,加入c之后,可能的组合有 ac、bc、abc、c。可以发现,插入c之后,以c结尾的组合的个数相当于原字符串的组合数+1。这是因为ab一共3种组合,将c分别拼接到3种组合尾部,是3种可能,c单独作为组合,是1种。
  • 性质②,对于一个字符串,比如abc,它的组合总数是 以a结尾的组合+以b结尾的组合+以c结尾的组合= a + (ab + b) + (ac + abc +bc +c)=1+2+4=7种。字符串的组合总数就是以各个字符结尾的组合之和。
  • 性质③,对于一个字符串,比如ab,在其后插入一个字符a,变成aba。出现重复字符的组合数,只与最后出现的重复字符有关。
  • 具体分析如下:对于ab的组合,我们已经分析过有3种组合。而aba,以最后一个a结尾的组合,有一些组合和之前的a重复。考虑剔除重复项,很简单,我们只考虑以最后一个a为结尾的组合,aa、ba、aba、a,我们发现,它包含了之前的a的所有组合。这个性质大家可以思考,是不是这样。其实是这样,我们只用考虑以最后一个a结尾的组合,就能得到所有以a结尾的组合了。
  • 这题我们使用性质①②③,就可以做题了。
  1. 我们先创建g[26]保存26个字母最后出现的位置。再创建一个total存组合的总数。
  2. 当前字符记作ch,这里我们再创建一个pre,存上一个重复字符的组合数。根据性质①以当前字符结尾的组合数=total+1,然后total变成total +(g[ch] - pre),或者说,组合总数=(之前的组合总数+(以当前字符结尾的组合数-上一个重复字符的组合数))。
  3. 重复上述操作,遍历整个字符串,最后的total即为所求。

四、代码分析

  • 觉得思路不清楚,可以看注释嗷。

五、AC

AC

六、复杂度分析

  1. 时间复杂度:O(n) ,n是字符串s的长度,O(n)是一次遍历字符串的时间复杂度。
  2. 空间复杂度:O(|C|),|C|对应26个小写字母,|C|=26,数组g[26]的空间复杂度是O(|C|)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

清墨韵染

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

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

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

打赏作者

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

抵扣说明:

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

余额充值