# 229小U的chi权值计算 O(n)做法

47 阅读2分钟

229小U的chi权值计算 O(n)做法

问题描述

给定一个由字符'c''h''i''?'组成的字符串,其中'?'可以替换为'c''h''i'。定义字符串的权值基于所有字符'h'的位置计算。对于每个'h',其前面的'c'和后面的'i'都会对其贡献 1 的权值。求所有可能替换方案的权值之和,结果对 (10^9 + 7) 取模。

解题思路

  1. 统计未知字符:首先统计字符串中 ? 的总数,用 cnt 表示。
  2. 前缀计数
    • prec 记录当前位置前面的 c 数量。
    • pre 记录前面 ? 的数量。
  3. 后缀计数
    • sufi 记录当前位置后面的 i 数量。
    • suf 记录后面 ? 的数量。
  4. 遍历字符串
    • 对于每个字符:
      • 如果是 c,则增加 prec
      • 如果是 i,则减少 sufi
      • 如果是 h,计算其贡献:
        • 固定 h 的贡献为 prec + sufi,乘以当前 ? 的排列组合数。每个 ? 都可以替换成 chi 这三种字符,所以总共的替换方案为 pow(3, cnt, mod)。因此前面的 ci 的贡献为 pow(3, cnt, mod) * (prec + sufi)
        • 考虑前面的 ? 替换为 c 和后面的 ? 替换为 i 的情况。前面的 ? 替换成 c 也有贡献,一个 ?pow(3, cnt - 1, mod) 种情况下可以替换成 c,而当前位置前面共有pre?,所以前面的 ? 的贡献为 pre * pow(3, cnt - 1, mod)。后面的 ? 同理为 suf * pow(3, cnt - 1, mod)
      • 如果是 ?,考虑其替换为 h 的情况,类似地计算贡献,并更新 presuf。当前的 ? 已经替换成了 h,所以后面的 ? 的贡献为 suf * pow(3, cnt - 2, mod)。前面的 ? 同理为 pre * pow(3, cnt - 2, mod)
  5. 取模:最终结果对 (10^9 + 7) 取模。

代码实现

mod = int(1e9 + 7)
def solution(s: str) -> int:
    pre = 0
    cnt = suf = s.count('?')
    prec = 0
    sufi = s.count('i')
    res = 0
    for i in range(len(s)):
        if s[i] == 'i':
            sufi -= 1
        elif s[i] == 'c':
            prec += 1
        elif s[i] == "h":
            res = (res + pow(3, cnt, mod) * (prec + sufi) + pre * pow(3, cnt - 1, mod) + suf * pow(3, cnt - 1, mod)) % mod
        else:
            suf -= 1
            res = (res + pow(3, cnt - 1, mod) * (prec + sufi) + pre * pow(3, cnt - 2, mod) + suf * pow(3, cnt - 2, mod)) % mod
            pre += 1
    return res



if __name__ == '__main__':
    print(solution("ch?hi") == 16)
    print(solution("ccch") == 3)
    print(solution("c?i") == 2)

复杂度分析

  • 时间复杂度:(O(n)),其中(n)是字符串的长度。(实现中可以预处理快速幂的结果,使每步计算都是(O(1))的时间复杂度)
  • 空间复杂度:(O(1)),只使用了常数额外空间。