子串分值和/贡献度/“子串分值”系列II

 

 题解:

先回忆一下“子串分值”系列I的“子串分值”题目是怎么做的:

题目中比较重要的信息就是 f的值仅受到在连续字串中出现一次的字符的影响。直接统计所有子串中单个字符的个数时间上过不去,那么,我们可以考虑单个字符带来的贡献度。(核心思想:换位思考)
看样例:‘ababc’
我们看第二个a,虽然它可以处于多个子串中,但是如果这个子串里面还包含了其它a的话,那么这个’a’就不能对f的值产生贡献(使f的总和增加)了。而它每处于一个有效子串(除开它自己没有别的a的子串)中,f的总值就增加1。

第二个a:
在子串‘aba*‘中对f值无贡献 (*表示任意后续,可为空)
在子串’a’,‘ab’,‘abc’,‘ba’,‘bab’,'babc’中均对f值贡献了1,总共贡献6

所以,我们统计每一个字符处于多少个有效子串中即可计算出f的总和。

如何计算有效子串呢?

还是看刚刚的第二个’a’,它所处的子串要有效,就得不能包含别的‘a‘。那么我们先找到不包含其他’a’的最长子串:‘babc’

现在要做的就是找到这个串中包含’a’的连续子串的个数,如何找呢?

可以这样考虑,由于要包含’a‘,那么子串中a前面的字符选择就有:

‘b’,’’(空) 共2种情况
后面的字符选择有:

’(空),‘b’,‘bc’ 共3种情况
那么子串的情况就有 2×3=6种。( 即(a前面的字符个数+1) × ( a后面的字符个数+1)或 (该’a’的下标 - 上个‘a’的下标)×(下个’a’的下标 - 该’a’的下标)
 

 与这道题不同的是,本题字串可以存在同一个字母,但要考虑到贡献度时,也应注意!

理解以下几点:

1.我们对每个字母的贡献值进行累加即可得到正确答案。

2.每个字母的贡献值:首先理解一下:对于任意一个在字符串中的字母,所有包含这个字母子串的个数算法:字母初始时“上一次“”出现的位置设为-1,(本次出现的位置-上次出现的位置)*(将来最近一次出现的位置-本次出现的位置),这个可以用题目例子枚举一下,然后就会发现这个式子的含义。解决了这个问题之后,还有一个“作用域”的问题(就是一个字母在什么范围内才会对结果做出贡献),在本题中,一个字母的作用域为:上次出现这个字母的位置——整个字符串结束(解释:当一个字母出现后,之后如果再出现,结果是不会增加的,所以之后再出现的字母对结果不做贡献。上次出现到---整个字符结束,这整个字符串及包含这个字母的子串(上面对此数量算法已作出解释)都要对结果做一次贡献。)

3.遍历字符串,计算每个字母的贡献值,累加即可。“子串分值”题类似思路,作用于不同而已。

这个思路是对于“子串分值”和“子串分值和”都通用的公式,在这个题中所谓的“将来最近一次出现的位置”就是字符串长度的位置。原因:一个字符出现,随后再出现,这个随后再出现是对结果不做贡献的,所以出不出现无所谓,可以直接滑到最后。但如果要考虑这个字母给整个子串带来的贡献度,仍要保证当前位置之前不具有相同字母。因此那个“将来最近一次出现的位置”直接写字符串长度就可以了。可以做一下“子串分值”那道题,可以有更深的理解) 

## 解题思路

请填写解题思路

```
import os
import sys

# 请在此输入您的代码
s=input()
node="a"
ans=0
while ord(node)<=ord("z"):
  li=[]
  if node in s:
    li.append(-1)
    for i in range(len(s)):
      if node==s[i]:
        li.append(i)
    li.append(len(s))
    for i in range(1,len(li)):
      ans+=(li[i]-li[i-1])*(li[-1]-li[i])
  node=chr(ord(node)+1)
print(ans)
```

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值