diff --git "a/Index/\345\223\210\345\270\214\350\241\250.md" "b/Index/\345\223\210\345\270\214\350\241\250.md" index 34da03b5..e8c53f6f 100644 --- "a/Index/\345\223\210\345\270\214\350\241\250.md" +++ "b/Index/\345\223\210\345\270\214\350\241\250.md" @@ -85,6 +85,7 @@ | [1742. 盒子中小球的最大数量](https://leetcode.cn/problems/maximum-number-of-balls-in-a-box/) | [LeetCode 题解链接](https://leetcode.cn/problems/maximum-number-of-balls-in-a-box/solution/by-ac_oier-3mxf/) | 简单 | 🤩🤩🤩 | | [1743. 从相邻元素对还原数组](https://leetcode-cn.com/problems/restore-the-array-from-adjacent-pairs/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/restore-the-array-from-adjacent-pairs/solution/gong-shui-san-xie-yi-ti-shuang-jie-dan-x-elpx/) | 中等 | 🤩🤩🤩🤩 | | [1748. 唯一元素的和](https://leetcode-cn.com/problems/sum-of-unique-elements/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/sum-of-unique-elements/solution/gong-shui-san-xie-yi-ti-shuang-jie-pai-x-atnd/) | 简单 | 🤩🤩🤩🤩 | +| [1781. 所有子字符串美丽值之和](https://leetcode.cn/problems/sum-of-beauty-of-all-substrings/) | [LeetCode 题解链接](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/) | 中等 | 🤩🤩🤩🤩 | | [1838. 最高频元素的频数](https://leetcode-cn.com/problems/frequency-of-the-most-frequent-element/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/frequency-of-the-most-frequent-element/solution/gong-shui-san-xie-cong-mei-ju-dao-pai-xu-kxnk/) | 中等 | 🤩🤩🤩 | | [1995. 统计特殊四元组](https://leetcode-cn.com/problems/count-special-quadruplets/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/count-special-quadruplets/solution/gong-shui-san-xie-yi-ti-si-jie-mei-ju-ha-gmhv/) | 简单 | 🤩🤩🤩🤩 | | [2006. 差的绝对值为 K 的数对数目](https://leetcode-cn.com/problems/count-number-of-pairs-with-absolute-difference-k/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/count-number-of-pairs-with-absolute-difference-k/solution/gong-shui-san-xie-jian-dan-mo-ni-ti-by-a-1jel/) | 简单 | 🤩🤩🤩🤩 | diff --git "a/Index/\346\250\241\346\213\237.md" "b/Index/\346\250\241\346\213\237.md" index f30b94a8..29b4802b 100644 --- "a/Index/\346\250\241\346\213\237.md" +++ "b/Index/\346\250\241\346\213\237.md" @@ -216,6 +216,7 @@ | [1763. 最长的美好子字符串](https://leetcode-cn.com/problems/longest-nice-substring/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/longest-nice-substring/solution/cong-shu-ju-fan-wei-xuan-ze-he-gua-suan-n3y2a/) | 简单 | 🤩🤩🤩 | | [1768. 交替合并字符串](https://leetcode.cn/problems/merge-strings-alternately/) | [LeetCode 题解链接](https://leetcode.cn/problems/merge-strings-alternately/solution/by-ac_oier-rjve/) | 简单 | 🤩🤩🤩 | | [1773. 统计匹配检索规则的物品数量](https://leetcode.cn/problems/count-items-matching-a-rule/) | [LeetCode 题解链接](https://leetcode.cn/problems/count-items-matching-a-rule/solution/by-ac_oier-qyd6/) | 简单 | 🤩🤩🤩 | +| [1781. 所有子字符串美丽值之和](https://leetcode.cn/problems/sum-of-beauty-of-all-substrings/) | [LeetCode 题解链接](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/) | 中等 | 🤩🤩🤩🤩 | | [1784. 检查二进制字符串字段](https://leetcode.cn/problems/check-if-binary-string-has-at-most-one-segment-of-ones/) | [LeetCode 题解链接](https://leetcode.cn/problems/check-if-binary-string-has-at-most-one-segment-of-ones/solution/by-ac_oier-kiu6/) | 简单 | 🤩🤩🤩 | | [1790. 仅执行一次字符串交换能否使两个字符串相等](https://leetcode.cn/problems/check-if-one-string-swap-can-make-strings-equal/) | [LeetCode 题解链接](https://leetcode.cn/problems/check-if-one-string-swap-can-make-strings-equal/solution/by-ac_oier-qeul/) | 简单 | 🤩🤩🤩🤩🤩 | | [1791. 找出星型图的中心节点](https://leetcode-cn.com/problems/find-center-of-star-graph/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/find-center-of-star-graph/solution/gong-shui-san-xie-jian-dan-mo-ni-ti-by-a-qoix/) | 简单 | 🤩🤩🤩 | diff --git "a/LeetCode/1691-1700/1697. \346\243\200\346\237\245\350\276\271\351\225\277\345\272\246\351\231\220\345\210\266\347\232\204\350\267\257\345\276\204\346\230\257\345\220\246\345\255\230\345\234\250\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/1691-1700/1697. \346\243\200\346\237\245\350\276\271\351\225\277\345\272\246\351\231\220\345\210\266\347\232\204\350\267\257\345\276\204\346\230\257\345\220\246\345\255\230\345\234\250\357\274\210\345\233\260\351\232\276\357\274\211.md" index 7544a30f..5c67f445 100644 --- "a/LeetCode/1691-1700/1697. \346\243\200\346\237\245\350\276\271\351\225\277\345\272\246\351\231\220\345\210\266\347\232\204\350\267\257\345\276\204\346\230\257\345\220\246\345\255\230\345\234\250\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/1691-1700/1697. \346\243\200\346\237\245\350\276\271\351\225\277\345\272\246\351\231\220\345\210\266\347\232\204\350\267\257\345\276\204\346\230\257\345\220\246\345\255\230\345\234\250\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -56,6 +56,8 @@ Tag : 「并查集」、「排序」、「双指针」 关于回答连通性问题,容易想到并查集。同时我们可以通过「调整回答询问的顺序」来降低复杂度(避免重复重置并查集和添加某些边),即转换为离线问题来处理。 +> 何为离线问题?预先知道所有询问,能够通过调整回答询问的顺序,来降低算法复杂度。同时不同询问相互独立,不会因为调整询问顺序,对每个询问的结果造成影响。例如莫队算法。 + 具体的,我们可以对边集 `es` 和所有询问 `qs` 分别按照「边权」以及「限制」排升序。为了排序后,仍能知道当前询问的原编号,我们要将所有的 `qs[i]` 转换为四元组。 随后从前往后处理每个询问 `qs[i] = (a, b, t, idx)`,同时使用变量 `j` 来记录当前处理到的边。在查询 `a` 和 `b` 是否连通前,先将边集 `es` 中所有所有边权小于 `t` 的边应用到并查集上,从而实现每次 `ans[idx] = query(a, b)` 查询到的是原图中所有边权小于限制值 `t` 的子图。 diff --git "a/LeetCode/1781-1790/1781. \346\211\200\346\234\211\345\255\220\345\255\227\347\254\246\344\270\262\347\276\216\344\270\275\345\200\274\344\271\213\345\222\214\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1781-1790/1781. \346\211\200\346\234\211\345\255\220\345\255\227\347\254\246\344\270\262\347\276\216\344\270\275\345\200\274\344\271\213\345\222\214\357\274\210\344\270\255\347\255\211\357\274\211.md" new file mode 100644 index 00000000..d37a8e28 --- /dev/null +++ "b/LeetCode/1781-1790/1781. \346\211\200\346\234\211\345\255\220\345\255\227\347\254\246\344\270\262\347\276\216\344\270\275\345\200\274\344\271\213\345\222\214\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -0,0 +1,133 @@ +### 题目描述 + +这是 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/)** ,难度为 **中等**。 + +Tag : 「模拟」、「哈希表」 + + + +一个字符串的 美丽值 定义为:出现频率最高字符与出现频率最低字符的出现次数之差。 + +比方说,`"abaacc"` 的美丽值为 `3 - 1 = 2`。 + +给你一个字符串 `s` ,请你返回它所有子字符串的 美丽值 之和。 + +示例 1: +``` +输入:s = "aabcb" + +输出:5 + +解释:美丽值不为零的字符串包括 ["aab","aabc","aabcb","abcb","bcb"] ,每一个字符串的美丽值都为 1 。 +``` +示例 2: +``` +输入:s = "aabcbaa" + +输出:17 +``` + +提示: +* $1 <= s.length <= 500$ +* `s` 只包含小写英文字母。 + +--- + +### 模拟 + 哈希表 + +数据范围只有 $500$,我们可以通过两层循环的方式枚举所有子串,当枚举子串左端点 `i` 的时候,可以同步开一个大小为 $C = 26$ 的数组来记录每个字母的出现次数,随后通过遍历该数组来得知最大和最小频次,将当前子串对应的美丽值累加到答案。 + +该做法复杂度为 $O(n^2 \times C)$,计算量约为 $500 \times 500 \times 26 = 6.5 \times 10^6$,可以过。 + +在确定了子串的左端点 `i`,枚举右端点 `j` 的过程中,维护最大频次是简单的,关键在于如果知晓最小频次,我们可以额外起一个哈希表 `map` 来记录出现频次为 `x` 的字符有多少个,`map[x] = cnt` 含义为频次为 `x` 的字符类型有 `cnt` 种。 + +假设当前我们处理的字符为 `c`,根据字符 `c` 原来的频次进行分情况讨论(使用 `max` 和 `min` 分别记录当前最大最小频次): + +* 若字符 `c` 为首次出现,即原频次为 $0$,此时有最小频次 `min = 1` +* 当字符 `c` 为并非首次出现,假设原频次数为 `x`,此时频次为 `x` 的字符数量减一;频次为 `x + 1` 的字符数量加一,若频次为 `x` 的字符数量在减一后 $map[min] \leq 0$,说明没有频次为 `min` 的字符了,此时最小频次为 `min + 1` + +Java 代码: +```Java +class Solution { + public int beautySum(String s) { + int n = s.length(), ans = 0; + for (int i = 0; i < n; i++) { + int[] cnts = new int[26]; + Map map = new HashMap<>(); + int min = -1, max = -1; + for (int j = i; j < n; j++) { + int c = s.charAt(j) - 'a'; + map.put(cnts[c], map.getOrDefault(cnts[c], 0) - 1); + map.put(cnts[c] + 1, map.getOrDefault(cnts[c] + 1, 0) + 1); + cnts[c]++; + if (cnts[c] == 1) min = 1; + else if (map.get(min) <= 0) min++; + max = Math.max(max, cnts[c]); + ans += max - min; + } + } + return ans; + } +} +``` +TypeScript 代码: +```TypeScript +function beautySum(s: string): number { + let n = s.length, ans = 0 + for (let i = 0; i < n; i++) { + const cnts = new Array(26).fill(0) + const map = new Map() + let min = 0, max = 0 + for (let j = i; j < n; j++) { + const c = s.charCodeAt(j) - 'a'.charCodeAt(0) + if (!map.has(cnts[c])) map.set(cnts[c], 0) + map.set(cnts[c], map.get(cnts[c]) - 1) + if (!map.has(cnts[c] + 1)) map.set(cnts[c] + 1, 0) + map.set(cnts[c] + 1, map.get(cnts[c] + 1) + 1) + cnts[c]++ + if (cnts[c] == 1) min = 1 + else if (map.get(min) <= 0) min++ + max = Math.max(max, cnts[c]) + ans += max - min + } + } + return ans +} +``` +Python 代码: +```Python +class Solution: + def beautySum(self, s: str) -> int: + n, ans = len(s), 0 + for i in range(n): + cnts = [0] * 26 + dmap = defaultdict(int) + maxv, minv = -1, -1 + for j in range(i, n): + c = ord(s[j]) - ord('a') + dmap[cnts[c]] -= 1 + dmap[cnts[c] + 1] += 1 + cnts[c] += 1 + if cnts[c] == 1: + minv = 1 + elif dmap[minv] <= 0: + minv += 1 + maxv = max(maxv, cnts[c]) + ans += maxv - minv + return ans +``` +* 时间复杂度:$O(n^2)$ +* 空间复杂度:$O(C)$,其中 $C = 26$ 为字符集大小 + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.1781` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 +