字符串模板

序号 问题 常用模板/思路 蓝桥杯真题 (链接)
1 统计不同字符个数 使用set集合存储字符,返回len(set)即可 不同子串 (2019 省赛) 子串分值 (2020 省赛)
2 判断是否有重复字符 利用set去重后比较长度,或用collections.Counter统计频次 重复字符串 (2020 国赛) 重复的串 (2024 国赛)
3 找出第一个只出现一次的字符 1. 用哈希表 (Counter) 统计频率 2. 再次遍历字符串,找到第一个频率为1的字符 字串分值 (2020 省赛) 找第一个只出现一次的字符
4 统计每个字符出现次数 使用collections.Counter直接生成频数字典 重复字符串 (2020 国赛) 子串分值和 (2020 省赛)
5 字符串去重 使用set进行去重(会丢失顺序) 或遍历字符串,维护一个seen集合和一个结果列表 子串去重 (2025 国赛) 串中取3个不重复字母
6 判断两个字符串字母相同 对两个字符串的字符进行排序 (sorted) 后比较是否相等 字符串对比 (基础练习)
7 最长无重复字符子串 滑动窗口 : 维护窗口,用集合/数组记录字符是否出现过,右指针扩展,遇重复则移动左指针 最长不重复子串 (省赛训练题) (此题为LeetCode经典题的蓝桥版)
8 拆分字符串使两部分不同字符之和最大 根据题目不同,常用前缀和思想 (预计算每个分割点前后的不同字符数)或暴力枚举分割点 切开字符串 (2015 国赛) 分割字符串 (2024 国赛

一个字符串的非空子串是指字符串中长度至少为

1

的连续的一段字符组成的串。例如,字符串

𝑎

𝑎

𝑎

𝑏

有非空子串

𝑎

,

𝑏

,

𝑎

𝑎

,

𝑎

𝑏

,

𝑎

𝑎

𝑎

,

𝑎

𝑎

𝑏

,

𝑎

𝑎

𝑎

𝑏

,一共

7

个。注意在计算时,只算本质不同的串的个数。

请问,字符串

0100110001010001

有多少个不同的非空子串?

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
  // 请在此输入您的代码
  set<string> a;
  string s="0100110001010001";
  
  for(int len=1;len<=s.size();len++){
    for(int i=0;i<=s.size()-len;i++){
      a.insert(s.substr(i,len));
    }
  }
  cout<<a.size();
  return 0;
}

子串分值和

题目描述

对于一个字符串

𝑆

,我们定义

𝑆

的分值

𝑓

(

𝑆

)

𝑆

中出现的不同的字符个数。例如

𝑓

(

"

𝑎

𝑏

𝑎

"

)

=

2

𝑓

(

"

𝑎

𝑏

𝑐

"

)

=

3

,

𝑓

(

"

𝑎

𝑎

𝑎

"

)

=

1

现在给定一个字符串

𝑆

0... 𝑛 − 1

(长度为

𝑛

),请你计算对于所有

𝑆

的非空子串

𝑆

𝑖 . . . 𝑗

(

0

𝑖

𝑗

<

𝑛

)

𝑓

(

𝑆

𝑖 . . . 𝑗

)

的和是多少。

输入描述

输入一行包含一个由小写字母组成的字符串

𝑆

其中,

1

𝑛

1

0

5

输出描述

输出一个整数表示答案。

输入输出样例

示例 1

输入

ababc

输出

28

只能过60%样例,

代码:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    string s;
    cin >> s;
    int n = s.size();
    long long ans = 0;
    for (int i = 0; i < n; ++i) {
        unordered_set<char> seen;  // 或者 set<char>
        for (int j = i; j < n; ++j) {
            seen.insert(s[j]);
            ans += seen.size();
        }
    }
    cout << ans << endl;
    return 0;
}

定义 dp[i] 表示以第 i 个字符结尾的所有子串的分值之和。

转移:dp[i] = dp[i-1] + (i - last[s[i]]),其中 last[c] 是字符 c 上一次出现的位置(初始为 -1)。

最后答案 = sum(dp[i])。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
int main() {
    string s; cin >> s;
    int n = s.size();
    vector<int> last(26, -1);
    long long ans = 0, dp = 0;
    for (int i = 0; i < n; ++i) {
        int c = s[i] - 'a';
        dp += i - last[c];
        ans += dp;
        last[c] = i;
    }
    cout << ans << endl;
    return 0;
}

三、

重复字符串

题目描述

如果一个字符串

𝑆

恰好可以由某个字符串重复

𝐾

次得到,我们就称

𝑆

𝐾

次重复字符串。例如 abcabcabc可以看作是 abc 重复

3

次得到,所以 abcabcabc 是

3

次重复字符串。

同理 aaaaaa 既是

2

次重复字符串、又是

3

次重复字符串和

6

次重复字符串。

现在给定一个字符串

𝑆

,请你计算最少要修改其中几个字符,可以使

𝑆

变为一个

𝐾

次字符串?

输入描述

输入第一行包含一个整数

𝐾

第二行包含一个只含小写字母的字符串

𝑆

其中,

1

𝐾

1

0

5

,

1

𝑆

1

0

5

。其中

𝑆

表示

𝑆

的 长度。

输出描述

输出一个整数代表答案。如果

𝑆

无法修改成

𝐾

次重复字符串,输出

1

输入输出样例

示例 1

输入

2

aabbaa

输出

2

对于这个问题,如果字符串长度 n 不是 K 的倍数,直接输出 -1。否则,令 m = n / K,将字符串分成 K 段,每段长度为 m。要使所有段完全相同,对于每个偏移位置 i(0 ≤ i < m),需要将第 0 段、第 1 段、......、第 K-1 段的第 i 个字符改成相同字符。统计这 K 个字符中出现次数最多的字符,保留它,其余 K - max_cnt 个字符需要修改。对所有 i 求和即得最少修改次数。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    int K;
    string S;
    cin >> K >> S;
    int n = S.size();
    if (n % K != 0) {
        cout << -1 << endl;
        return 0;
    }
    int m = n / K;
    int ans = 0;
    for (int i = 0; i < m; ++i) {
        int cnt[26] = {0};
        for (int j = 0; j < K; ++j) {
            char c = S[j * m + i];
            cnt[c - 'a']++;
        }
        int maxcnt = *max_element(cnt, cnt + 26);
        ans += K - maxcnt;
    }
    cout << ans << endl;
    return 0;
}
相关推荐
Fcy6482 小时前
算法基础详解(六)倍增思想与离散化思想
算法·快速幂·离散化·倍增算法
wuweijianlove2 小时前
算法调度问题中的代价模型与优化方法的技术5
算法
Dxy12393102162 小时前
Python路径算法简介
开发语言·python·算法
And_Ii2 小时前
LCR 132.砍竹子Ⅱ
算法
汀、人工智能2 小时前
[特殊字符] 第67课:跳跃游戏II
数据结构·算法·数据库架构·图论·bfs·跳跃游戏ii
Little At Air3 小时前
LeetCode 30. 串联所有单词的子串 | 困难 C++实现
算法·leetcode·职场和发展
手握风云-3 小时前
优选算法的层序之径:队列专题
数据结构·算法·leetcode
Yiyi_Coding3 小时前
一致性哈希算法
算法·哈希算法