2025届蓝桥杯c++A组真题----好串的数目

题目描述

对于一个长度为 n 的字符串 s=s0​s1​⋯sn−1​ 来说,子串的定义是从中选出两个下标 l,r (0≤l≤r≤n−1),这之间所有的字符组合起来的一个新的字符串:s′=sl​sl+1​⋯sr​ 就是其中一个子串。

现在给出一个只有数字字符 0∼9 组成的数字字符串,小蓝想要知道在其所有的子串中,有多少个子串是好串。一个子串是好串,当且仅当它满足以下两个条件之一:

  1. 单字符子串一定是好串,即当子串长度为 1 时,它总是好串;
  2. 长度大于 1 时,可以拆分为两个连续非递减子串: 一个串 p=p0​p1​⋯pk−1​ 为连续非递减子串是指,对于所有 1≤i<k,满足 pi​=pi−1​ 或 pi​=pi−1​+1。即数字串中的每一个数字,要么等于上一个数字,要么等于上一个数字加 1。例如 12233456 是连续非递减子串。

输入格式

输入一行包含一个字符串 s。

输出格式

输出一行包含一个整数表示答案,即好串的数目。

输入输出样例

输入 

12258

输出 

12

说明/提示

样例说明 1

  • 长度为 1 的好串:12258,共 5 个;
  • 长度为 2 的好串:12222558,共 4 个;
  • 长度为 3 的好串:122225,共 2 个;
  • 长度为 4 的好串:1225,共 1 个;

总计 5+4+2+1=12 个。

思路:滑动窗口

对于连续的好串需要满足s[r]=s[r-1]+1或者s[r]=s[r-1]   

一个子串是“好串”的条件是:

1. 长度为 1。
2. 可以拆分为 最多 两个连续的非递减子串。
关键在于条件 2。“可以拆分为最多两个连续的非递减子串”意味着这个子串内部 最多只允许出现一个“断点” 。“断点”指的是相邻两个字符 s[i-1] 和 s[i] 不满足非递减关系(即 s[i] 既不等于 s[i-1] 也不等于 s[i-1] + 1 )。

代码利用滑动窗口 [l, r] 来维护一个子串,并保证这个窗口内的子串始终最多只包含一个“断点”。

我们用一个变量来统计这个断点。

#include <bits/stdc++.h> 

using namespace std;
#define int long long
const int nn = 100005; // 定义一个常量,表示字符串最大长度+缓冲区
string s;

signed main() {

    cin >> s;

    int cnt = 0; //断点数
    int l = 0;   // 滑动窗口的左边界指针,初始指向字符串开头
    int ans = 0; 

    // s[r] 用于判断是否到达字符串末尾 (空字符 '\0')
    for (int r = 0; s[r]; r++) {

        // 检查新加入窗口的字符 s[r] 是否与前一个字符 s[r-1] 构成了“断点”
        // r > 0 是为了防止访问 s[-1]
        // 条件:s[r] 既不等于 s[r-1],也不等于 s[r-1] + 1
        if (r > 0 && s[r - 1] + 1 != s[r] && s[r - 1] != s[r]) {
            cnt++; // 如果是断点,+1
        }

        // 当窗口内的断点数量超过 1 时,需要收缩左边界
        while (cnt > 1) {
             l++; // 将左边界向右移动一位

            // 检查即将移出窗口的那个“断点”是否发生在 l 处
            // 注意:这里比较的是 s[l] 和 s[l-1] 的关系
            // 如果 s[l] 和 s[l-1] 之间存在断点,那么当 l 向右移动一位后,
            // 这个断点就不在窗口 [l+1, r] 内了,所以断点计数器需要减 1
            // 并且需要 l > 0 (因为 l=0 时 l-1 是 -1)
            if (s[l] != s[l - 1] && s[l - 1] + 1 != s[l]) {
                 cnt--; // 断点计数器减 1
            }
        }

        // 到这里,窗口 [l, r] 内的断点数量保证为 0 或 1
        // 这意味着所有以 r 结尾,且起始位置在 [l, r] 区间内的子串都是“好串”
        // 例如,子串 s[l..r], s[l+1..r], ..., s[r..r] 都是好串
        // 这些子串的数量是 r - l + 1
        ans += (r - l + 1); // 将这些好串的数量累加到总答案中
    }

    cout << ans << '\n'; // 输出最终的好串总数
    return 0; 
}

和博主上篇文章思路类似,有兴趣也可以看一下哦,链接:力扣209. 长度最小的子数组-CSDN博客

感谢看到这里,喜欢博主可以点点关注,感谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值