【子串分值和】贡献度的理解;细节的考虑

子串分值和

审题: f ( s ) = 字符串 s 中有多少个不同的字符 f(s) = 字符串 s 中有多少个不同的字符 f(s)=字符串s中有多少个不同的字符

理解:每个字符的 “贡献值”

举例:
对于 a b a b c 的第 2 次出现的 a,有多少字符串包含这个a呢?
a 的左侧:a b a、b a、a(把 a 本身算成 a 的左侧)
a 的右侧:a b、a b c
所以,一共有 2 * 3 = 6 种字符串包含这个 a。

但是,这些字符串都会把这个 a 计数吗?显然不会。那么,有多少字符串会把这个 a 算入 f ( s ) f(s) f(s) 呢?

只有这个 a 是第一次出现时,才会对它计数。即:a b a 并不会对第 2 个 a 计数。

所以,这个 a 的贡献度是:从这个 a 往左数到 a,从这个 a 往右数到末尾(对于后面来说,这个 a 是第一次出现的),然后相乘,积就是这个 a 的贡献值。

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    
    
	public static void main(String[] args) {
    
    
		Scanner scan = new Scanner(System.in);
		// 在此输入您的代码...
		String string = scan.nextLine();
		char[] cArray = string.toCharArray();
		int[] leftIndex = new int[26];
		Arrays.fill(leftIndex, -1);

		long count = 0;
		int len = cArray.length;
		for (int i = 0; i < len; i++) {
    
    
			char c = cArray[i];
			count += (long) (len - i) * (i - leftIndex[c - 'a']);
			leftIndex[c - 'a'] = i;
		}
		System.out.print(count);
		scan.close();
	}

}

细节

  1. “贡献值” 如何计算?
    举例:a b a b c,计算中间 a 贡献值。
    a 的左侧有:b a,a(2)
    a 的右侧有:a b c,a b(2)

    那么是不是就是 2 * 2 呢?

    不是!我们并没有考虑单独的左侧或者右侧作为字符串的情况。

    我们看似把单独的 a 只放在了左侧,其实右侧也需要一个单独的 a。这是因为: b a 也是该 a 有贡献的子字符串,或者说 a 本身也是该 a 有贡献的字符串。可是在之前的计算中,如果取左侧单独的a,就必须和右侧的 a b c,a b 进行组合。所以,右侧也需要有一个单独的 a,这样在乘法时就可以实现 11、n1、1*n。

  2. 初识 leftIndex 为什么初始化为 -1?
    计算贡献值的时候,比如第一个a的index=0,那么index - leftIndex = 1,所以为-1

  3. 关于long的使用

    1 ≤ n ≤ 105

    这意味着在计算 count 时,有105*105超过 int 的风险。
    所以:

    1. count 设为 long
    2. count += (long) (len - i) * (i - leftIndex[c - 'a']);

猜你喜欢

转载自blog.csdn.net/m0_60641871/article/details/129888363