返回介绍

solution / 2800-2899 / 2842.Count K-Subsequences of a String With Maximum Beauty / README

发布于 2024-06-17 01:02:59 字数 9325 浏览 0 评论 0 收藏 0

2842. 统计一个字符串的 k 子序列美丽值最大的数目

English Version

题目描述

给你一个字符串 s 和一个整数 k 。

k 子序列指的是 s 的一个长度为 k 的 子序列 ,且所有字符都是 唯一 的,也就是说每个字符在子序列里只出现过一次。

定义 f(c) 为字符 c 在 s 中出现的次数。

k 子序列的 美丽值 定义为这个子序列中每一个字符 c 的 f(c) 之  。

比方说,s = "abbbdd" 和 k = 2 ,我们有:

  • f('a') = 1, f('b') = 3, f('d') = 2
  • s 的部分 k 子序列为:
    • "_ab_bbdd" -> "ab" ,美丽值为 f('a') + f('b') = 4
    • "_a_bbb_d_d" -> "ad" ,美丽值为 f('a') + f('d') = 3
    • "a_b_bb_d_d" -> "bd" ,美丽值为 f('b') + f('d') = 5

请你返回一个整数,表示所有 k 子序列 里面 美丽值 是 最大值 的子序列数目。由于答案可能很大,将结果对 109 + 7 取余后返回。

一个字符串的子序列指的是从原字符串里面删除一些字符(也可能一个字符也不删除),不改变剩下字符顺序连接得到的新字符串。

注意:

  • f(c) 指的是字符 c 在字符串 s 的出现次数,不是在 k 子序列里的出现次数。
  • 两个 k 子序列如果有任何一个字符在原字符串中的下标不同,则它们是两个不同的子序列。所以两个不同的 k 子序列可能产生相同的字符串。

 

示例 1:

输入:s = "bcca", k = 2
输出:4
解释:s 中我们有 f('a') = 1 ,f('b') = 1 和 f('c') = 2 。
s 的 k 子序列为:
_bc_ca ,美丽值为 f('b') + f('c') = 3
_b_c_c_a ,美丽值为 f('b') + f('c') = 3
_b_cc_a_ ,美丽值为 f('b') + f('a') = 2
b_c_c_a_ ,美丽值为 f('c') + f('a') = 3
bc_ca_ ,美丽值为 f('c') + f('a') = 3
总共有 4 个 k 子序列美丽值为最大值 3 。
所以答案为 4 。

示例 2:

输入:s = "abbcd", k = 4
输出:2
解释:s 中我们有 f('a') = 1 ,f('b') = 2 ,f('c') = 1 和 f('d') = 1 。
s 的 k 子序列为:
_ab_b_cd_ ,美丽值为 f('a') + f('b') + f('c') + f('d') = 5
ab_bcd_ ,美丽值为 f('a') + f('b') + f('c') + f('d') = 5 
总共有 2 个 k 子序列美丽值为最大值 5 。
所以答案为 2 。

 

提示:

  • 1 <= s.length <= 2 * 105
  • 1 <= k <= s.length
  • s 只包含小写英文字母。

解法

方法一:贪心 + 组合数学

我们先用哈希表 $f$ 统计字符串 $s$ 中每个字符的出现次数,即 $f[c]$ 表示字符 $c$ 在字符串 $s$ 中出现的次数。

由于 $k$ 子序列是字符串 $s$ 中一个长度为 $k$ 的子序列,且字符唯一,因此,如果 $f$ 中不同字符的个数小于 $k$,那么不存在 $k$ 子序列,直接返回 $0$ 即可。

否则,要使得 $k$ 子序列的美丽值最大,我们需要尽可能地让美丽值大的字符尽可能地多地出现在 $k$ 子序列中。因此,我们可以对 $f$ 中的值进行倒序排序,得到一个数组 $vs$。

我们记数组 $vs$ 第 $k$ 个字符的出现次数为 $val$,一共有 $x$ 个字符出现的次数为 $val$。

那么我们先找出出现次数大于 $val$ 的字符,将每个字符出现的次数相乘,得到初始答案 $ans$,剩余的需要选取的字符个数更新为 $k$。我们需要从 $x$ 个字符中选取 $k$ 个字符,因此答案需要乘上组合数 $C_x^k$,最后再乘上 $val^k$,即 $ans = ans \times C_x^k \times val^k$。

注意,这里需要用到快速幂,以及取模操作。

时间复杂度 $O(n)$,空间复杂度 $O(|\Sigma|)$。其中 $n$ 是字符串的长度,而 $\Sigma$ 是字符集。本题中字符集为小写字母,因此 $|\Sigma| = 26$。

class Solution:
  def countKSubsequencesWithMaxBeauty(self, s: str, k: int) -> int:
    f = Counter(s)
    if len(f) < k:
      return 0
    mod = 10**9 + 7
    vs = sorted(f.values(), reverse=True)
    val = vs[k - 1]
    x = vs.count(val)
    ans = 1
    for v in vs:
      if v == val:
        break
      k -= 1
      ans = ans * v % mod
    ans = ans * comb(x, k) * pow(val, k, mod) % mod
    return ans
class Solution {
  private final int mod = (int) 1e9 + 7;

  public int countKSubsequencesWithMaxBeauty(String s, int k) {
    int[] f = new int[26];
    int n = s.length();
    int cnt = 0;
    for (int i = 0; i < n; ++i) {
      if (++f[s.charAt(i) - 'a'] == 1) {
        ++cnt;
      }
    }
    if (cnt < k) {
      return 0;
    }
    Integer[] vs = new Integer[cnt];
    for (int i = 0, j = 0; i < 26; ++i) {
      if (f[i] > 0) {
        vs[j++] = f[i];
      }
    }
    Arrays.sort(vs, (a, b) -> b - a);
    long ans = 1;
    int val = vs[k - 1];
    int x = 0;
    for (int v : vs) {
      if (v == val) {
        ++x;
      }
    }
    for (int v : vs) {
      if (v == val) {
        break;
      }
      --k;
      ans = ans * v % mod;
    }
    int[][] c = new int[x + 1][x + 1];
    for (int i = 0; i <= x; ++i) {
      c[i][0] = 1;
      for (int j = 1; j <= i; ++j) {
        c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
      }
    }
    ans = ((ans * c[x][k]) % mod) * qpow(val, k) % mod;
    return (int) ans;
  }

  private long qpow(long a, int n) {
    long ans = 1;
    for (; n > 0; n >>= 1) {
      if ((n & 1) == 1) {
        ans = ans * a % mod;
      }
      a = a * a % mod;
    }
    return ans;
  }
}
class Solution {
public:
  int countKSubsequencesWithMaxBeauty(string s, int k) {
    int f[26]{};
    int cnt = 0;
    for (char& c : s) {
      if (++f[c - 'a'] == 1) {
        ++cnt;
      }
    }
    if (cnt < k) {
      return 0;
    }
    vector<int> vs(cnt);
    for (int i = 0, j = 0; i < 26; ++i) {
      if (f[i]) {
        vs[j++] = f[i];
      }
    }
    sort(vs.rbegin(), vs.rend());
    const int mod = 1e9 + 7;
    long long ans = 1;
    int val = vs[k - 1];
    int x = 0;
    for (int v : vs) {
      x += v == val;
    }
    for (int v : vs) {
      if (v == val) {
        break;
      }
      --k;
      ans = ans * v % mod;
    }
    int c[x + 1][x + 1];
    memset(c, 0, sizeof(c));
    for (int i = 0; i <= x; ++i) {
      c[i][0] = 1;
      for (int j = 1; j <= i; ++j) {
        c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
      }
    }
    auto qpow = [&](long long a, int n) {
      long long ans = 1;
      for (; n; n >>= 1) {
        if (n & 1) {
          ans = ans * a % mod;
        }
        a = a * a % mod;
      }
      return ans;
    };
    ans = (ans * c[x][k] % mod) * qpow(val, k) % mod;
    return ans;
  }
};
func countKSubsequencesWithMaxBeauty(s string, k int) int {
  f := [26]int{}
  cnt := 0
  for _, c := range s {
    f[c-'a']++
    if f[c-'a'] == 1 {
      cnt++
    }
  }
  if cnt < k {
    return 0
  }
  vs := []int{}
  for _, x := range f {
    if x > 0 {
      vs = append(vs, x)
    }
  }
  sort.Slice(vs, func(i, j int) bool {
    return vs[i] > vs[j]
  })
  const mod int = 1e9 + 7
  ans := 1
  val := vs[k-1]
  x := 0
  for _, v := range vs {
    if v == val {
      x++
    }
  }
  for _, v := range vs {
    if v == val {
      break
    }
    k--
    ans = ans * v % mod
  }
  c := make([][]int, x+1)
  for i := range c {
    c[i] = make([]int, x+1)
    c[i][0] = 1
    for j := 1; j <= i; j++ {
      c[i][j] = (c[i-1][j-1] + c[i-1][j]) % mod
    }
  }
  qpow := func(a, n int) int {
    ans := 1
    for ; n > 0; n >>= 1 {
      if n&1 == 1 {
        ans = ans * a % mod
      }
      a = a * a % mod
    }
    return ans
  }
  ans = (ans * c[x][k] % mod) * qpow(val, k) % mod
  return ans
}
function countKSubsequencesWithMaxBeauty(s: string, k: number): number {
  const f: number[] = new Array(26).fill(0);
  let cnt = 0;
  for (const c of s) {
    const i = c.charCodeAt(0) - 97;
    if (++f[i] === 1) {
      ++cnt;
    }
  }
  if (cnt < k) {
    return 0;
  }
  const mod = BigInt(10 ** 9 + 7);
  const vs: number[] = f.filter(v => v > 0).sort((a, b) => b - a);
  const val = vs[k - 1];
  const x = vs.filter(v => v === val).length;
  let ans = 1n;
  for (const v of vs) {
    if (v === val) {
      break;
    }
    --k;
    ans = (ans * BigInt(v)) % mod;
  }
  const c: number[][] = new Array(x + 1).fill(0).map(() => new Array(k + 1).fill(0));
  for (let i = 0; i <= x; ++i) {
    c[i][0] = 1;
    for (let j = 1; j <= Math.min(i, k); ++j) {
      c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % Number(mod);
    }
  }
  const qpow = (a: bigint, n: number): bigint => {
    let ans = 1n;
    for (; n; n >>>= 1) {
      if (n & 1) {
        ans = (ans * a) % BigInt(mod);
      }
      a = (a * a) % BigInt(mod);
    }
    return ans;
  };
  ans = (((ans * BigInt(c[x][k])) % mod) * qpow(BigInt(val), k)) % mod;
  return Number(ans);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文