|
| 1 | +### 题目描述 |
| 2 | + |
| 3 | +这是 LeetCode 上的 **[1781. 所有子字符串美丽值之和](https://acoier.com/2022/12/12/1780.%20%E5%88%A4%E6%96%AD%E4%B8%80%E4%B8%AA%E6%95%B0%E5%AD%97%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E8%A1%A8%E7%A4%BA%E6%88%90%E4%B8%89%E7%9A%84%E5%B9%82%E7%9A%84%E5%92%8C%EF%BC%88%E4%B8%AD%E7%AD%89%EF%BC%89/)** ,难度为 **中等**。 |
| 4 | + |
| 5 | +Tag : 「模拟」、「哈希表」 |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +一个字符串的 美丽值 定义为:出现频率最高字符与出现频率最低字符的出现次数之差。 |
| 10 | + |
| 11 | +比方说,`"abaacc"` 的美丽值为 `3 - 1 = 2`。 |
| 12 | + |
| 13 | +给你一个字符串 `s` ,请你返回它所有子字符串的 美丽值 之和。 |
| 14 | + |
| 15 | +示例 1: |
| 16 | +``` |
| 17 | +输入:s = "aabcb" |
| 18 | + |
| 19 | +输出:5 |
| 20 | + |
| 21 | +解释:美丽值不为零的字符串包括 ["aab","aabc","aabcb","abcb","bcb"] ,每一个字符串的美丽值都为 1 。 |
| 22 | +``` |
| 23 | +示例 2: |
| 24 | +``` |
| 25 | +输入:s = "aabcbaa" |
| 26 | + |
| 27 | +输出:17 |
| 28 | +``` |
| 29 | + |
| 30 | +提示: |
| 31 | +* 1ドル <= s.length <= 500$ |
| 32 | +* `s` 只包含小写英文字母。 |
| 33 | + |
| 34 | +--- |
| 35 | + |
| 36 | +### 模拟 + 哈希表 |
| 37 | + |
| 38 | +数据范围只有 500ドル,ドル我们可以通过两层循环的方式枚举所有子串,当枚举子串左端点 `i` 的时候,可以同步开一个大小为 $C = 26$ 的数组来记录每个字母的出现次数,随后通过遍历该数组来得知最大和最小频次,将当前子串对应的美丽值累加到答案。 |
| 39 | + |
| 40 | +该做法复杂度为 $O(n^2 \times C),ドル计算量约为 500ドル \times 500 \times 26 = 6.5 \times 10^6,ドル可以过。 |
| 41 | + |
| 42 | +在确定了子串的左端点 `i`,枚举右端点 `j` 的过程中,维护最大频次是简单的,关键在于如果知晓最小频次,我们可以额外起一个哈希表 `map` 来记录出现频次为 `x` 的字符有多少个,`map[x] = cnt` 含义为频次为 `x` 的字符类型有 `cnt` 种。 |
| 43 | + |
| 44 | +假设当前我们处理的字符为 `c`,根据字符 `c` 原来的频次进行分情况讨论(使用 `max` 和 `min` 分别记录当前最大最小频次): |
| 45 | + |
| 46 | +* 若字符 `c` 为首次出现,即原频次为 0ドル,ドル此时有最小频次 `min = 1` |
| 47 | +* 当字符 `c` 为并非首次出现,假设原频次数为 `x`,此时频次为 `x` 的字符数量减一;频次为 `x + 1` 的字符数量加一,若频次为 `x` 的字符数量在减一后 $map[min] \leq 0,ドル说明没有频次为 `min` 的字符了,此时最小频次为 `min + 1` |
| 48 | + |
| 49 | +Java 代码: |
| 50 | +```Java |
| 51 | +class Solution { |
| 52 | + public int beautySum(String s) { |
| 53 | + int n = s.length(), ans = 0; |
| 54 | + for (int i = 0; i < n; i++) { |
| 55 | + int[] cnts = new int[26]; |
| 56 | + Map<Integer, Integer> map = new HashMap<>(); |
| 57 | + int min = -1, max = -1; |
| 58 | + for (int j = i; j < n; j++) { |
| 59 | + int c = s.charAt(j) - 'a'; |
| 60 | + map.put(cnts[c], map.getOrDefault(cnts[c], 0) - 1); |
| 61 | + map.put(cnts[c] + 1, map.getOrDefault(cnts[c] + 1, 0) + 1); |
| 62 | + cnts[c]++; |
| 63 | + if (cnts[c] == 1) min = 1; |
| 64 | + else if (map.get(min) <= 0) min++; |
| 65 | + max = Math.max(max, cnts[c]); |
| 66 | + ans += max - min; |
| 67 | + } |
| 68 | + } |
| 69 | + return ans; |
| 70 | + } |
| 71 | +} |
| 72 | +``` |
| 73 | +TypeScript 代码: |
| 74 | +```TypeScript |
| 75 | +function beautySum(s: string): number { |
| 76 | + let n = s.length, ans = 0 |
| 77 | + for (let i = 0; i < n; i++) { |
| 78 | + const cnts = new Array<number>(26).fill(0) |
| 79 | + const map = new Map() |
| 80 | + let min = 0, max = 0 |
| 81 | + for (let j = i; j < n; j++) { |
| 82 | + const c = s.charCodeAt(j) - 'a'.charCodeAt(0) |
| 83 | + if (!map.has(cnts[c])) map.set(cnts[c], 0) |
| 84 | + map.set(cnts[c], map.get(cnts[c]) - 1) |
| 85 | + if (!map.has(cnts[c] + 1)) map.set(cnts[c] + 1, 0) |
| 86 | + map.set(cnts[c] + 1, map.get(cnts[c] + 1) + 1) |
| 87 | + cnts[c]++ |
| 88 | + if (cnts[c] == 1) min = 1 |
| 89 | + else if (map.get(min) <= 0) min++ |
| 90 | + max = Math.max(max, cnts[c]) |
| 91 | + ans += max - min |
| 92 | + } |
| 93 | + } |
| 94 | + return ans |
| 95 | +} |
| 96 | +``` |
| 97 | +Python 代码: |
| 98 | +```Python |
| 99 | +class Solution: |
| 100 | + def beautySum(self, s: str) -> int: |
| 101 | + n, ans = len(s), 0 |
| 102 | + for i in range(n): |
| 103 | + cnts = [0] * 26 |
| 104 | + dmap = defaultdict(int) |
| 105 | + maxv, minv = -1, -1 |
| 106 | + for j in range(i, n): |
| 107 | + c = ord(s[j]) - ord('a') |
| 108 | + dmap[cnts[c]] -= 1 |
| 109 | + dmap[cnts[c] + 1] += 1 |
| 110 | + cnts[c] += 1 |
| 111 | + if cnts[c] == 1: |
| 112 | + minv = 1 |
| 113 | + elif dmap[minv] <= 0: |
| 114 | + minv += 1 |
| 115 | + maxv = max(maxv, cnts[c]) |
| 116 | + ans += maxv - minv |
| 117 | + return ans |
| 118 | +``` |
| 119 | +* 时间复杂度:$O(n^2)$ |
| 120 | +* 空间复杂度:$O(C),ドル其中 $C = 26$ 为字符集大小 |
| 121 | + |
| 122 | +--- |
| 123 | + |
| 124 | +### 最后 |
| 125 | + |
| 126 | +这是我们「刷穿 LeetCode」系列文章的第 `No.1781` 篇,系列开始于 2021年01月01日,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 |
| 127 | + |
| 128 | +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 |
| 129 | + |
| 130 | +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 |
| 131 | + |
| 132 | +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 |
| 133 | + |
0 commit comments