30,360
社区成员
发帖
与我相关
我的任务
分享
题目描述
对于一个字符串 S,我们定义 S 的分值 f(S) 为 S 中恰好出现一次的字符个数。例如 f(aba) = 1,f(abc) = 3, f(aaa) = 0。现在给定一个字符串 (长度为 n,),请你计算对于所有 S 的非空子串 (0≤i≤j<n),的和是多少。
输入描述
输入一行包含一个由小写字母组成的字符串 S。输出描述
输出一个整数表示答案。输入输出样例
输入ababc
输出21
找出所有可能的子串;
统计每个子串的分值
考虑枚举字符串的每个字符对答案的贡献。让第i个字符能对答案产生贡献,必须子串中该字符只出现一次。对哪些子串第i个字符只出现一次?看看下图分析。
【做法】定义left_index表示第i个字符上一次出现的位置,right_index表示第i个字符下一次出现的位置。那么要让第i个字符能对答案产生贡献(即该子串内第i个字符只恰好出现一次的),则包含它的子串的左端点的取值范围必须在[left_index + 1 , i]之间,右端点的取值范围必须在[i+1, right_index - 1]之间。
chars = input()
len_str = len(chars)
left = [None for _ in range(len_str)] # 左边第一次出现的相同字符
right = [None for _ in range(len_str)] # 右边第一次出现的相同字符
for i in range(len_str): # 遍历所有字符,统计每个字符的贡献
char = chars[i]
for j in range(i - 1, -1, -1): # 向左边找左端点
left_char = chars[j]
if left_char == char: # 出现相同的字符
left[i] = j # 保存到left
break
for j in range(i + 1, len_str): # 向右边找右端点
right_char = chars[j]
if right_char == char: # 出现相同的字符
right[i] = j # 保存到right
break
result = 0
for i in range(len_str):
if left[i] == None and right[i] == None: # 左右端点没有相同字符(从头到尾只有一个字符)
result += (i + 1) * (len_str - i) # 组合:左边*右边
elif left[i] == None: # 只有左边全没相同
result += (i + 1) * (right[i] - i) # 组合:左边*右边(没有)
elif right[i] == None: # 只有右边全没相同
result += (i - left[i]) * (len_str - i) # 组合:左边(没有)*右边
else: # 只有都有相同的
result += (right[i] - i) * (i - left[i])# 把左右没有相同的部分组合:左边(没有)*右边(没有)
print(result)