题目描述
对于一个字符串 �S,我们定义 �S 的分值 �(�)f(S) 为 �S 中恰好出现一次的字符个数。例如 �(���)=1,�(���)=3,�(���)=0f(aba)=1,f(abc)=3,f(aaa)=0。
现在给定一个字符串 �0⋯�−1S0⋯n−1(长度为 �n,1≤�≤1051≤n≤105),请你计算对于所有 �S 的非空子串 ��⋯�(0≤�≤�<�)Si⋯j(0≤i≤j<n),�(��⋯�)f(Si⋯j) 的和是多少。
输入描述
输入一行包含一个由小写字母组成的字符串 �S。
输出描述
输出一个整数表示答案。
输入输出样例
示例
输入
ababc
输出
21
运行限制
最大运行时间:1s
最大运行内存: 256M
题目分析:
题目给出了一个字符串,找出子串中一个字符出现一次的总个数。这道题刚看的时候想直接用暴力把他干掉。暴力思路就是直接套两层for循环,外循环代表着子串的有边界,内循环代表着子串的左边界。然后我们取出这个子串,我们在去找里面只出现一次的字符,然后我们把他们全部加起来就是最后结果。但是这个嘞会超时,只能拿到40分,不过在比赛的时候,如果想不到优化,这样子就可以,直接来一手骗分。优化的思路呢: 算出每个字符做出的贡献,先一层循环i,然后 在用两根指针right,left,left向左遍历,right向右遍历,当s[left]==s[i] 就退出向左和向右的遍历,然后这个相对应的字符做出的贡献就是(left+1)*(right+1),然后每个字符做出的贡献全部相加,就是结果了
AC代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in) ;
String s = scanner.next();
char[] chars = s.toCharArray();
int len = chars.length ;
int res= 0 ;
for(int i =0 ;i<len;i++){
int left =0 ;
int right = 0 ;
char c = chars[i];
for (int j = i-1 ; j>=0 && chars[j]!=c;j--){
left++ ;
}
for (int k = i+1 ; k<len&& chars[k]!=c ; k++){
right++ ;
}
res += (left+1)*(right+1) ;
}
System.out.println(res);
scanner.close();
}
}