6050. 字符串的总引力(子串分值和)

简介: 笔记

前言


实际上这是蓝桥真题,和子串分值和一样


子串分值和


题目描述

对于一个字符串S ,我们定义S {S}S的分值f ( S ) 为S 中出现的不同的字符个数。例如f ( " a b c " ) = 3 , f ( " a b a " ) = 2 , f ( " a a a " ) = 1


现在给定一个字符串S ,请你计算所有S {S}S的非空子串S [ i . . . j ] ( 0 ≤ i ≤ j < n ) ,f ( S [ i . . . j ] ) 的和是多少。


输入描述

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

其中,1 ≤ n ≤ 1 0 5


输出描述

输出一个整数表示答案。


样例

输入#1

ababc


输出#1

28


输入#2

code


输出#2

20


思路

6.png

在此,我们定义贡献wi为:包含当前字符且当前字符之前不在含有该字符的所有字符串的个数。


这是我自己给的定义,应该很抽象。


以样例一举例说明:a b a b c ,第二个a 对答案的贡献是多少?


可以算得结果是 6 :


ba

bab

babc

a

ab

abc


为什么这样是对的?(也就是左边有限制(到左边过去第一个同字符),右边无限制(一直到字符串末尾))


不会证明,但是如果前面还含有该字符,当前字符是不在产生贡献的。(因为在计算之前那个字符的时候,已经包含了当前字符的情况)。而且这样不重不漏的包含了所有情况数。


题解

法一:计算贡献

我们用a数组来记录字符最后出现的位置。

下标从0开始,所以对于字符第一次出现,左侧应该是 i + 1 个字符,那么初始化 a数组为−1就很好的解决了。

class Solution {
public:
    long long appealSum(string s) {
        int n = s.size();
        int a[26];
        memset(a, -1, sizeof a);
        long long res = 0;
        for (int i = 0; i < n; i++) {
            int x = s[i] - 'a';
            res += (i - a[x]) * (n - i);
            a[x] = i;
        }
        return res;
    }
};

法二:动态规划7.png

class Solution {
public:
    long long appealSum(string s) {
        int n = s.size();
        vector<int> a(26, -1);
        vector<int> f(n, 0);
        f[0] = 1;
        a[s[0] - 'a'] = 0;
        for (int i = 1; i < n; i++) {
            int x = s[i] - 'a';
            f[i] = f[i - 1] + i - a[x];
            a[x] = i;
        }
        long long res = 0;
        for (int i = 0; i < n; i++) res += f[i];
        return res;
    }
};

优化掉一维数组:

class Solution {
public:
    long long appealSum(string s) {
        vector<int> a(26, -1);
        long long num = 0, res = 0;
        for (int i = 0; i < s.size(); i++) {
            int x = s[i] - 'a';
            num += i - a[x];
            res += num;
            a[x] = i;
        }
        return res;
    }
};

子串分值


题目描述

8.png

输入描述

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


输出描述

输出一个整数表示答案。


样例

输入#1

ababc


输出#1

21


思路

9.png

题解

#include <bits/stdc++.h>
using namespace std;
int main() {
    string s; cin >> s;
    int n = s.size();
  vector<int> a[26];
    s = '@' + s;
    for (int i = 1; i <= n; i++) {
        int x = s[i] - 'a';
        if (a[x].size() == 0) a[x].push_back(0);
        a[x].push_back(i);
    }
    for (int i = 0; i < 26; i++) {
        if (a[i].size()) a[i].push_back(n + 1);
    }
    int res = 0;
    for (int i = 0; i < 26; i++) {
        auto& v = a[i];
        if (!v.size()) continue;
        for (int j = 1; j < v.size() - 1; j++)
          res += (v[j] - v[j - 1]) * (v[j + 1] - v[j]);
    }
    cout << res << endl;
    return 0;
}


相关文章
|
7月前
|
存储 C语言
最长的指定瑕疵度的元音子串
最长的指定瑕疵度的元音子串
|
7月前
|
机器学习/深度学习 算法 测试技术
【组合数学 容斥原理 逆向思考】2930. 重新排列后包含指定子字符串的字符串数目
【组合数学 容斥原理 逆向思考】2930. 重新排列后包含指定子字符串的字符串数目
|
7月前
|
算法 测试技术 C++
【贪心 堆 】3081. 替换字符串中的问号使分数最小
【贪心 堆 】3081. 替换字符串中的问号使分数最小
|
7月前
|
算法 测试技术 C#
C++前缀和算法:统计美丽子字符串
C++前缀和算法:统计美丽子字符串
|
7月前
【每日一题Day226】L1156单字符重复子串的最大长度 | 贪心+滑动窗口
【每日一题Day226】L1156单字符重复子串的最大长度 | 贪心+滑动窗口
61 0
|
7月前
|
算法 程序员 索引
【算法训练-动态规划 三】【双序列DP问题】最长重复子数组、最长公共子串、最长公共子序列、编辑距离
【算法训练-动态规划 三】【双序列DP问题】最长重复子数组、最长公共子串、最长公共子序列、编辑距离
114 0
|
7月前
|
存储 算法 程序员
【算法训练-字符串 一】【子串问题】最长无重复子串、最长回文子串、最长公共前缀
【算法训练-字符串 一】【子串问题】最长无重复子串、最长回文子串、最长公共前缀
72 0
|
C++
子串分值和
对于一个字符串 S,我们定义 S 的分值 f (S ) 为 S 中出现的不同的字符个数。
62 0
|
算法
1304 字符串的相似度 后缀数组
1304 字符串的相似度 后缀数组
73 0
|
算法 C++
【动态规划篇】最少分割回文 && 编辑距离 && 不同的子序列
【动态规划篇】最少分割回文 && 编辑距离 && 不同的子序列
【动态规划篇】最少分割回文 && 编辑距离 && 不同的子序列