课后自主练习(递归)1061. 统计特定字串模式的个数 medium《编程思维与实践》个人学习笔记

题目

在 0 和 1 组成的长度为n(1<=n<=31)的字符串中,统计包含m(1<=m<=n)个连续 1 子串的字符串的个数。
在这里插入图片描述
数据
1 1
2 1
3 1
4 3
10 3
10 5
20 10
20 15
31 20
31 1
-1 -1

思路

当m>n时候 0,n全是1也无法凑出来满足的字符串
当m==n时候 1,有且只有一个满足的字符
当m<n时候 我们假设满足条件的字符串为f(m,n)
当n变成n+1的时候

不难发现,在f(m,n)的基础上无论加1或者加0,得到的新的字符串都满足题目要求的“存在连续m个数字都是1”这个条件


但是我们发现当 长度为n的字符串的末尾m-1个数字都恰好为1(且倒是第m个数字是0的时候)的时候,我们再加上一个1,就会导致新生成的n+1长度的字符串的末尾恰好有m个字符串
满足该字符串(末尾m-1个数字是1,倒数第m个数字是0)的情况有 2 n − m − 1 种 2^{n-m-1}种 2nm1

注意:倘若在前n-m-1中的数字里面存在连续m个字符串,那么这种情况已经被情况①包含了,所以我们需要减去对应的已经被情况①包含的情况。
f ( m , n − m − 1 ) f(m,n-m-1) f(m,nm1)

所以我们可以得到递推关系
f ( m , n + 1 ) = 2 f ( m , n ) + 2 n − m − 1 − f ( m , n − m − 1 ) f(m,n+1) = 2f(m,n) +2^{n-m-1} - f(m,n-m-1) f(m,n+1)=2f(m,n)+2nm1f(m,nm1)

代码(递归)

ll RE(int n, int m)
{
    if(n < m) return 0;
    if(n == m) return 1;

    return 2 * RE(n - 1,m) + pow(2, n-m-1) - RE(n - m - 1,m);
}

代码(迭代)

#include<iostream>
#include<cmath>
#include<cstring>
#define ll long long
using namespace std;

ll IT(int n , int m)
{
    ll *arr = new ll[n + 1];
    memset(arr,0,8*n+8);
    for(int i = 1; i < n + 1; i++)
    {
        if(i < m)
        {arr[i] = 0;}
        else if(i == m)
        {arr[i] = 1;}
        else if(i > m)
        {
            arr[i] = arr[i - 1] * 2 + pow(2,i - m - 1) - arr[i - m - 1];
        }
    }
    ll temp = arr[n];
    delete[] arr;
    return temp;
}


int main()
{
    ll n, m;
    while(cin >> n >> m)
    {
        if(n == -1 && m == -1)
            break;

        
        cout << IT(n,m) << endl;
        //cout << RE(n,m) << endl;
    }    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值