子串分值 题目链接
由于数学公式无法复制,所以题目完整描述请点击原题链接查看
试题 历届试题 子串分值
资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
对于一个字符串 ,我们定义 的分值 为 中恰好出现一次的字符个数。例如 “aba”,“abc”, “aaa”。
现在给定一个字符串 (长度为 ),请你计算对于所有 的非空子串 ,的和是多少。
输入格式
输入一行包含一个由小写字母组成的字符串 。
输出格式
输出一个整数表示答案。
样例输入
ababc
Data
样例输出
21
Data
样例说明
子串 f值
a 1
ab 2
aba 1
abab 0
ababc 1
b 1
ba 2
bab 1
babc 2
a 1
ab 2
abc 3
b 1
bc 2
c 1
注意:还有一个题是本科B组省赛题【子串分值和】,两个题有点不同不过原理大同小异。
思路::求每个字符左边无重复的字符数乘右边无重复字符数。
就拿题中数据举例,ababc逐个字母计算贡献度,结果如下
左边就是截至到上次重复出现的位置的字母数(包括本身),右边就是截至到下次重复出现的位置的字母数字母数(包括本身)
左边 右边
a 1 2
b 2 2
a 2 3
b 2 2
c 5 1
所有字母贡献度相加=2+4+6+4+5=21;
例1:首字母a,就是a和b,a,b,c的有序且连续的排列组合,且都要包含首字母a得出
a 1
ab 2
2个结果
例2:第二个字母b
就是a和b和a的有序且连续组合且都要包含第二个字母b,并且此字母只出现一次,得出
ab 2
aba 1
b 1
ba 2
4个结果
例3:第三个字母a
就是b和a和b,c的有序且连续组合且都要包含第三个字母a,并且此字母只出现一次,得出
ba 2
bab 2
babc 3
a 1
ab 2
abc 3
6个结果
可以总结出,一个字母贡献度等于前面字符数量+当前字符和 后面字符数量+当前字符 乘积,其中前面字符数量截止到上次本字母出现位置,后面字符数量截止到下次本字母出现位置,因为每个组合的可能都要包含当前字母,所有在计算时加上当前字母,就得出
字母贡献度=(左边字符数(截止到当前字母上次出现位置)+1)*右边字符数(截止到当前字母下次出现位置)+1)。
欢迎交流谈论,有更好的方法和更通俗易懂的思路都可以互相交流进步
代码实现:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
int nums[] = new int[26];
s = "0" + s;
int n = s.length();
long sum = 0;
long a1, a2;
for (int i = 1; i < n; i++) {
a1 = i - nums[s.charAt(i) - 'a']; // 每个字符左边贡献度
// 求每个字符右边贡献度
int j = i + 1;
while (true) {
//如果找到下次重复的字符或者找到字符串末端则跳出循环
if (j >= n || s.charAt(j) == s.charAt(i)) {
break;
}else {
j++;
}
}
//右边字符贡献数=下次重复出现字符-当前字符下标
a2 = j - i;
//左右两边贡献度相乘得出单个字符的贡献度
sum+=a1*a2;
//记录本字符出现位置
nums[s.charAt(i) - 'a'] = i;
}
System.out.println(sum);
}
}