diff --git "a/Index/\344\272\214\345\210\206.md" "b/Index/\344\272\214\345\210\206.md" index 811edc60..1bab100b 100644 --- "a/Index/\344\272\214\345\210\206.md" +++ "b/Index/\344\272\214\345\210\206.md" @@ -66,6 +66,7 @@ | [1707. 与数组中元素的最大异或值](https://leetcode-cn.com/problems/maximum-xor-with-an-element-from-array/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/maximum-xor-with-an-element-from-array/solution/gong-shui-san-xie-jie-zhe-ge-wen-ti-lai-lypqr/) | 困难 | 🤩🤩🤩 | | [1713. 得到子序列的最少操作次数](https://leetcode-cn.com/problems/minimum-operations-to-make-a-subsequence/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/minimum-operations-to-make-a-subsequence/solution/gong-shui-san-xie-noxiang-xin-ke-xue-xi-oj7yu/) | 困难 | 🤩🤩🤩 | | [1751. 最多可以参加的会议数目 II](https://leetcode-cn.com/problems/maximum-number-of-events-that-can-be-attended-ii/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/maximum-number-of-events-that-can-be-attended-ii/solution/po-su-dp-er-fen-dp-jie-fa-by-ac_oier-88du/) | 困难 | 🤩🤩🤩 | +| [1760. 袋子里最少数目的球](https://leetcode.cn/problems/minimum-limit-of-balls-in-a-bag/) | [LeetCode 题解链接](https://acoier.com/2022/12/23/1760.%20%E8%A2%8B%E5%AD%90%E9%87%8C%E6%9C%80%E5%B0%91%E6%95%B0%E7%9B%AE%E7%9A%84%E7%90%83%EF%BC%88%E4%B8%AD%E7%AD%89%EF%BC%89/) | 中等 | 🤩🤩🤩🤩🤩 | | [1818. 绝对差值和](https://leetcode-cn.com/problems/minimum-absolute-sum-difference/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/minimum-absolute-sum-difference/solution/gong-shui-san-xie-tong-guo-er-fen-zhao-z-vrmq/) | 中等 | 🤩🤩🤩🤩🤩 | | [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/) | 中等 | 🤩🤩🤩 | | [1894. 找到需要补充粉笔的学生编号](https://leetcode-cn.com/problems/find-the-student-that-will-replace-the-chalk/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/find-the-student-that-will-replace-the-chalk/solution/gong-shui-san-xie-yi-ti-shuang-jie-qian-kpqsk/) | 中等 | 🤩🤩🤩🤩 | diff --git "a/Index/\345\217\214\346\214\207\351\222\210.md" "b/Index/\345\217\214\346\214\207\351\222\210.md" index fcf8000a..576f1dd9 100644 --- "a/Index/\345\217\214\346\214\207\351\222\210.md" +++ "b/Index/\345\217\214\346\214\207\351\222\210.md" @@ -68,6 +68,7 @@ | [1697. 检查边长度限制的路径是否存在](https://leetcode.cn/problems/checking-existence-of-edge-length-limited-paths/) | [LeetCode 题解链接](https://acoier.com/2022/12/14/1697.%20%E6%A3%80%E6%9F%A5%E8%BE%B9%E9%95%BF%E5%BA%A6%E9%99%90%E5%88%B6%E7%9A%84%E8%B7%AF%E5%BE%84%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%EF%BC%88%E5%9B%B0%E9%9A%BE%EF%BC%89/) | 困难 | 🤩🤩🤩🤩 | | [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/) | 简单 | 🤩🤩🤩🤩 | +| [1759. 统计同构子字符串的数目](https://leetcode.cn/problems/count-number-of-homogenous-substrings/) | [LeetCode 题解链接](https://acoier.com/2022/12/26/1759.%20%E7%BB%9F%E8%AE%A1%E5%90%8C%E6%9E%84%E5%AD%90%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E6%95%B0%E7%9B%AE%EF%BC%88%E4%B8%AD%E7%AD%89%EF%BC%89/) | 中等 | 🤩🤩🤩🤩 | | [1764. 通过连接另一个数组的子数组得到一个数组](https://leetcode-cn.com/problems/form-array-by-concatenating-subarrays-of-another-array/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/form-array-by-concatenating-subarrays-of-another-array/solution/clean-solutionni-jue-dui-neng-kan-dong-d-l4ts/) | 中等 | 🤩🤩🤩🤩 | | [2000. 反转单词前缀](https://leetcode-cn.com/problems/reverse-prefix-of-word/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/reverse-prefix-of-word/solution/gong-shui-san-xie-jian-dan-shuang-zhi-zh-dp9u/) | 简单 | 🤩🤩🤩🤩 | | [2024. 考试的最大困扰度](https://leetcode-cn.com/problems/maximize-the-confusion-of-an-exam/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/maximize-the-confusion-of-an-exam/solution/by-ac_oier-2rii/) | 中等 | 🤩🤩🤩🤩 | diff --git "a/Index/\346\225\260\345\255\246.md" "b/Index/\346\225\260\345\255\246.md" index 6a73d860..9e26a06c 100644 --- "a/Index/\346\225\260\345\255\246.md" +++ "b/Index/\346\225\260\345\255\246.md" @@ -79,6 +79,7 @@ | [1720. 解码异或后的数组](https://leetcode-cn.com/problems/decode-xored-array/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/decode-xored-array/solution/gong-shui-san-xie-li-yong-yi-huo-xing-zh-p1bi/) | 简单 | 🤩🤩🤩 | | [1734. 解码异或后的排列](https://leetcode-cn.com/problems/decode-xored-permutation/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/decode-xored-permutation/solution/gong-shui-san-xie-note-bie-pian-li-yong-zeh6o/) | 中等 | 🤩🤩🤩🤩 | | [1738. 找出第 K 大的异或坐标值](https://leetcode-cn.com/problems/find-kth-largest-xor-coordinate-value/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/find-kth-largest-xor-coordinate-value/solution/gong-shui-san-xie-xiang-jie-li-yong-er-w-ai0d/) | 中等 | 🤩🤩🤩 | +| [1759. 统计同构子字符串的数目](https://leetcode.cn/problems/count-number-of-homogenous-substrings/) | [LeetCode 题解链接](https://acoier.com/2022/12/26/1759.%20%E7%BB%9F%E8%AE%A1%E5%90%8C%E6%9E%84%E5%AD%90%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E6%95%B0%E7%9B%AE%EF%BC%88%E4%B8%AD%E7%AD%89%EF%BC%89/) | 中等 | 🤩🤩🤩🤩 | | [1775. 通过最少操作次数使数组的和相等](https://leetcode.cn/problems/equal-sum-arrays-with-minimum-number-of-operations/) | [LeetCode 题解链接](https://acoier.com/2022/12/09/1775.%20%E9%80%9A%E8%BF%87%E6%9C%80%E5%B0%91%E6%93%8D%E4%BD%9C%E6%AC%A1%E6%95%B0%E4%BD%BF%E6%95%B0%E7%BB%84%E7%9A%84%E5%92%8C%E7%9B%B8%E7%AD%89%EF%BC%88%E4%B8%AD%E7%AD%89%EF%BC%89/) | 中等 | 🤩🤩🤩🤩 | | [1780. 判断一个数字是否可以表示成三的幂的和](https://leetcode.cn/problems/check-if-number-is-a-sum-of-powers-of-three/) | [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/) | 中等 | 🤩🤩🤩🤩🤩 | | [剑指 Offer 44. 数字序列中某一位的数字](https://leetcode.cn/problems/shu-zi-xu-lie-zhong-mou-yi-wei-de-shu-zi-lcof/) | [LeetCode 题解链接](https://leetcode.cn/problems/shu-zi-xu-lie-zhong-mou-yi-wei-de-shu-zi-lcof/solution/by-ac_oier-wgr8/) | 中等 | 🤩🤩🤩🤩 | diff --git "a/LeetCode/1751-1760/1759. \347\273\237\350\256\241\345\220\214\346\236\204\345\255\220\345\255\227\347\254\246\344\270\262\347\232\204\346\225\260\347\233\256\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1751-1760/1759. \347\273\237\350\256\241\345\220\214\346\236\204\345\255\220\345\255\227\347\254\246\344\270\262\347\232\204\346\225\260\347\233\256\357\274\210\344\270\255\347\255\211\357\274\211.md" new file mode 100644 index 00000000..e8069575 --- /dev/null +++ "b/LeetCode/1751-1760/1759. \347\273\237\350\256\241\345\220\214\346\236\204\345\255\220\345\255\227\347\254\246\344\270\262\347\232\204\346\225\260\347\233\256\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -0,0 +1,123 @@ +### 题目描述 + +这是 LeetCode 上的 **[1759. 统计同构子字符串的数目](https://acoier.com/2022/12/26/1759.%20%E7%BB%9F%E8%AE%A1%E5%90%8C%E6%9E%84%E5%AD%90%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E6%95%B0%E7%9B%AE%EF%BC%88%E4%B8%AD%E7%AD%89%EF%BC%89/)** ,难度为 **中等**。 + +Tag : 「双指针」、「数学」 + + + +给你一个字符串 `s`,返回 `s` 中 同构子字符串 的数目。由于答案可能很大,只需返回对 $10^9 + 7$ 取余 后的结果。 + +同构字符串 的定义为:如果一个字符串中的所有字符都相同,那么该字符串就是同构字符串。 + +子字符串 是字符串中的一个连续字符序列。 + +示例 1: +``` +输入:s = "abbcccaa" + +输出:13 + +解释:同构子字符串如下所列: +"a" 出现 3 次。 +"aa" 出现 1 次。 +"b" 出现 2 次。 +"bb" 出现 1 次。 +"c" 出现 3 次。 +"cc" 出现 2 次。 +"ccc" 出现 1 次。 +3 + 1 + 2 + 1 + 3 + 2 + 1 = 13 +``` +示例 2: +``` +输入:s = "xy" + +输出:2 + +解释:同构子字符串是 "x" 和 "y" 。 +``` +示例 3: +``` +输入:s = "zzzzz" + +输出:15 +``` + +提示: +* $1 <= s.length <= 10^5$ +* `s` 由小写字符串组成 + + +--- + +### 双指针 + 数学 + +根据题意,我们需要找出 `s` 中所有字符相同的连续段。 + +假设 $s[i...(j - 1)]$ 为某个连续段,长度为 $m$,根据「等差数列求和」可知该连续段所能提供的同构字符串数量为 $\frac{(1 + m) \times m}{2}$。 + +具体的,我们可以从前往后扫描 `s`,假设当前处理到的位置为 `i`,将其看作连续段的左端点,然后从 `i` 出发找到当前最长连续段的右端点 `j - 1`,统计 $s[i...(j - 1)]$ 所能贡献同构字符串数量,并调整下个发起点为 $i = j$ 以扫描下一个连续段。 + +Java 代码: +```Java +class Solution { + public int countHomogenous(String s) { + int n = s.length(), MOD = (int)1e9+7; + long ans = 0; + for (int i = 0; i < n; ) { + int j = i; + while (j < n && s.charAt(j) == s.charAt(i)) j++; + long cnt = j - i; + ans += (1 + cnt) * cnt / 2; + ans %= MOD; + i = j; + } + return (int) ans; + } +} +``` +TypeScript 代码: +```TypeScript +function countHomogenous(s: string): number { + let n = s.length, mod = 1e9+7, ans = 0 + for (let i = 0; i < n; ) { + let j = i + while (j < n && s.charAt(j) == s.charAt(i)) j++ + const cnt = j - i + ans += (1 + cnt) * cnt / 2 + ans %= mod + i = j + } + return ans +} +``` +Python3 代码: +```Python3 +class Solution: + def countHomogenous(self, s: str) -> int: + n, mod, i, ans = len(s), 1e9+7, 0, 0 + while i < n: + j = i + while j < n and s[j] == s[i]: + j += 1 + cnt = j - i + ans += (cnt + 1) * cnt / 2 + ans %= mod + i = j + return int(ans) +``` +* 时间复杂度:$O(n)$ +* 空间复杂度:$O(1)$ + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.1759` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 + diff --git "a/LeetCode/1751-1760/1760. \350\242\213\345\255\220\351\207\214\346\234\200\345\260\221\346\225\260\347\233\256\347\232\204\347\220\203\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1751-1760/1760. \350\242\213\345\255\220\351\207\214\346\234\200\345\260\221\346\225\260\347\233\256\347\232\204\347\220\203\357\274\210\344\270\255\347\255\211\357\274\211.md" new file mode 100644 index 00000000..3be27b5e --- /dev/null +++ "b/LeetCode/1751-1760/1760. \350\242\213\345\255\220\351\207\214\346\234\200\345\260\221\346\225\260\347\233\256\347\232\204\347\220\203\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -0,0 +1,140 @@ +### 题目描述 + +这是 LeetCode 上的 **[1760. 袋子里最少数目的球](https://acoier.com/2022/12/23/1760.%20%E8%A2%8B%E5%AD%90%E9%87%8C%E6%9C%80%E5%B0%91%E6%95%B0%E7%9B%AE%E7%9A%84%E7%90%83%EF%BC%88%E4%B8%AD%E7%AD%89%EF%BC%89/)** ,难度为 **中等**。 + +Tag : 「二分」 + + + +给你一个整数数组 `nums`,其中 `nums[i]` 表示第 `i` 个袋子里球的数目。同时给你一个整数 `maxOperations`。 + +你可以进行如下操作至多 `maxOperations` 次: + +* 选择任意一个袋子,并将袋子里的球分到 `2` 个新的袋子中,每个袋子里都有 正整数 个球。 + * 比方说,一个袋子里有 `5` 个球,你可以把它们分到两个新袋子里,分别有 `1` 个和 `4` 个球,或者分别有 `2` 个和 `3` 个球。 + 你的开销是单个袋子里球数目的 最大值 ,你想要 最小化 开销。 + +请你返回进行上述操作后的最小开销。 + +示例 1: +``` +输入:nums = [9], maxOperations = 2 + +输出:3 + +解释: +- 将装有 9 个球的袋子分成装有 6 个和 3 个球的袋子。[9] -> [6,3] 。 +- 将装有 6 个球的袋子分成装有 3 个和 3 个球的袋子。[6,3] -> [3,3,3] 。 +装有最多球的袋子里装有 3 个球,所以开销为 3 并返回 3 。 +``` +示例 2: +``` +输入:nums = [2,4,8,2], maxOperations = 4 + +输出:2 + +解释: +- 将装有 8 个球的袋子分成装有 4 个和 4 个球的袋子。[2,4,8,2] -> [2,4,4,4,2] 。 +- 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,4,4,4,2] -> [2,2,2,4,4,2] 。 +- 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,2,2,4,4,2] -> [2,2,2,2,2,4,2] 。 +- 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,2,2,2,2,4,2] -> [2,2,2,2,2,2,2,2] 。 +装有最多球的袋子里装有 2 个球,所以开销为 2 并返回 2 。 +``` +示例 3: +``` +输入:nums = [7,17], maxOperations = 2 + +输出:7 +``` + +提示: +* $1 <= nums.length <= 10^5$ +* $1 <= maxOperations, nums[i] <= 10^9$ + +--- + +### 二分 + +最小化不超过 `max` 次划分操作后的单个袋子最大值,我们将其称为「划分值」。 + +**答案具有二段性:若使用 $k \leq \max$ 次划分操作后可达到最小划分值,此时减少划分操作次数,会使得划分值非单调上升。** + +因此我们可以二分答案,从而将问题进行等价转换: + +**假设当前二分到的值为 $limit$,我们需要实现一个线性复杂度为 `check` 函数,判断能否使用不超过 $\max$ 次划分次数,来使得划分值不超过 $limit$**: + +* 若能满足,说明 $[limit, +\infty]$ 范围的划分值,均能使用不超过 $\max$ 次的实现,此时让 $r = limit$ +* 若不能满足,比 $limit$ 更小的划分值,则更无法在 $\max$ 次操作中满足,说明 $[1, limit]$ 范围划分值均不是答案,此时让 $l = limit + 1$ + +考虑如何实现 `check` 函数,从前往后处理每个 $nums[i]$,根据 $nums[i]$ 与当前限制 $limit$ 的大小关系进行分情况讨论: + +* 若 $nums[i] \leq limit$:说明当前袋子不会成为瓶颈,无须消耗划分次数 +* 若 $nums[i] > limit$:此时需要对当前袋子进行划分,直到满足单个袋子球的数量不超过 $limit$ 为止,由于每次划分相当于增加一个袋子,而将 $nums[i]$ 划分成若干个不超过 $limit$ 个球的袋子,需要 $\left \lceil \frac{nums[i]}{limit} \right \rceil$ 个袋子,减去原本的一个,共需要增加 $\left \lceil \frac{nums[i]}{limit} \right \rceil$ 个新袋子,即划分 $\left \lceil \frac{nums[i]}{limit} \right \rceil$ 次 + + +Java 代码: +```Java +class Solution { + public int minimumSize(int[] nums, int max) { + int l = 1, r = 0x3f3f3f3f; + while (l < r) { + int mid = l + r >> 1; + if (check(nums, mid, max)) r = mid; + else l = mid + 1; + } + return r; + } + boolean check(int[] nums, int limit, int max) { + int cnt = 0; + for (int x : nums) cnt += Math.ceil(x * 1.0 / limit) - 1; + return cnt <= max; + } +} +``` +TypeScript 代码: +```TypeScript +function minimumSize(nums: number[], max: number): number { + function check(nums: number[], limit: number, max: number): boolean { + let cnt = 0 + for (const x of nums) cnt += Math.ceil(x / limit) - 1 + return cnt <= max + } + let l = 1, r = 0x3f3f3f3f + while (l < r) { + const mid = l + r >> 1 + if (check(nums, mid, max)) r = mid + else l = mid + 1 + } + return r +} +``` +Python 代码: +```Python +class Solution: + def minimumSize(self, nums: List[int], maxv: int) -> int: + def check(nums, limit, maxv): + return sum([(x + limit - 1) // limit - 1 for x in nums]) <= maxv + l, r = 1, 0x3f3f3f3f + while l < r: + mid = l + r >> 1 + if check(nums, mid, maxv): + r = mid + else: + l = mid + 1 + return r +``` +* 时间复杂度:$O(n \log{M})$,其中 $M = 1e9$ 为值域大小 +* 空间复杂度:$O(1)$ + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.1758` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 + diff --git "a/LeetCode/1761-1770/1764. \351\200\232\350\277\207\350\277\236\346\216\245\345\217\246\344\270\200\344\270\252\346\225\260\347\273\204\347\232\204\345\255\220\346\225\260\347\273\204\345\276\227\345\210\260\344\270\200\344\270\252\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1761-1770/1764. \351\200\232\350\277\207\350\277\236\346\216\245\345\217\246\344\270\200\344\270\252\346\225\260\347\273\204\347\232\204\345\255\220\346\225\260\347\273\204\345\276\227\345\210\260\344\270\200\344\270\252\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" index 2fdbabe9..14d795bc 100644 --- "a/LeetCode/1761-1770/1764. \351\200\232\350\277\207\350\277\236\346\216\245\345\217\246\344\270\200\344\270\252\346\225\260\347\273\204\347\232\204\345\255\220\346\225\260\347\273\204\345\276\227\345\210\260\344\270\200\344\270\252\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/1761-1770/1764. \351\200\232\350\277\207\350\277\236\346\216\245\345\217\246\344\270\200\344\270\252\346\225\260\347\273\204\347\232\204\345\255\220\346\225\260\347\273\204\345\276\227\345\210\260\344\270\200\344\270\252\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,84 +6,82 @@ Tag : 「双指针」 -给你一个长度为 n 的二维整数数组 groups ,同时给你一个整数数组 nums 。 +给你一个长度为 `n` 的二维整数数组 `groups` ,同时给你一个整数数组 `nums` 。 -你是否可以从 nums 中选出 n 个 不相交 的子数组,使得第 i 个子数组与 groups[i] (下标从 0 开始)完全相同,且如果 i > 0 ,那么第 (i-1) 个子数组在 nums 中出现的位置在第 i 个子数组前面。(也就是说,这些子数组在 nums 中出现的顺序需要与 groups 顺序相同) +你是否可以从 `nums` 中选出 `n` 个 不相交 的子数组,使得第 `i` 个子数组与 `groups[i]` (下标从 `0` 开始)完全相同,且如果 `i > 0` ,那么第 (`i-1`) 个子数组在 `nums` 中出现的位置在第 `i` 个子数组前面。(也就是说,这些子数组在 `nums` 中出现的顺序需要与 `groups` 顺序相同) -如果你可以找出这样的 n 个子数组,请你返回 true ,否则返回 false 。 +如果你可以找出这样的 `n` 个子数组,请你返回 `true` ,否则返回 `false`。 -如果不存在下标为 k 的元素 nums[k] 属于不止一个子数组,就称这些子数组是 不相交 的。子数组指的是原数组中连续元素组成的一个序列。 +如果不存在下标为 `k` 的元素 `nums[k]` 属于不止一个子数组,就称这些子数组是 不相交 的。子数组指的是原数组中连续元素组成的一个序列。 示例 1: ``` 输入:groups = [[1,-1,-1],[3,-2,0]], nums = [1,-1,0,1,-1,-1,3,-2,0] + 输出:true + 解释:你可以分别在 nums 中选出第 0 个子数组 [1,-1,0,1,-1,-1,3,-2,0] 和第 1 个子数组 [1,-1,0,1,-1,-1,3,-2,0] 。 这两个子数组是不相交的,因为它们没有任何共同的元素。 ``` 示例 2: ``` 输入:groups = [[10,-2],[1,2,3,4]], nums = [1,2,3,4,10,-2] + 输出:false + 解释:选择子数组 [1,2,3,4,10,-2] 和 [1,2,3,4,10,-2] 是不正确的,因为它们出现的顺序与 groups 中顺序不同。 [10,-2] 必须出现在 [1,2,3,4] 之前。 ``` 示例 3: ``` 输入:groups = [[1,2,3],[3,4]], nums = [7,7,1,2,3,4,7,7] + 输出:false + 解释:选择子数组 [7,7,1,2,3,4,7,7] 和 [7,7,1,2,3,4,7,7] 是不正确的,因为它们不是不相交子数组。 它们有一个共同的元素 nums[4] (下标从 0 开始)。 ``` 提示: -* groups.length == n -* 1 <= n <= $10^3$ -* 1 <= groups[i].length, sum(groups[i].length) <= $10^3$ -* 1 <= nums.length <= $10^3$ -* -$10^7$ <= groups[i][j], nums[k] <= $10^7$ +* $groups.length == n$ +* $1 <= n <= 10^3$ +* $1 <= groups[i].length, sum(groups[i].length) <= 10^3$ +* $1 <= nums.length <= 10^3$ +* $-10^7 <= groups[i][j], nums[k] <= 10^7$ --- -### 朴素解法 - -![image.png](https://pic.leetcode-cn.com/1613886675-qpyJVn-image.png) - -本质上是道模拟题。 +### 双指针 -使用 `i` 指针代表 `nums` 当前枚举到的位置;`j` 代表 `groups` 中枚举到哪个数组。 +为了方便,将 `groups` 记为 `gs`。 -`cnt` 代表匹配的数组个数。 +从前往后处理每个 $gs[i]$,使用 `idx` 记录当前使用到 `nums` 中的哪一位(即 $[0, ... (idx - 1)]$ 的 $nums[i]$ 已经用于匹配 $gs[0, ... (i - 1)]$。 -* 当 `i` 开头的连续一段和 `groups[j]` 匹配:`j` 指针右移一位(代表匹配下一个数组),`i` 指针右移 `groups[j].length` 长度。 -* 当 `i` 开头的连续一段和 `groups[j]` 不匹配:`i` 右移一位。 +每次尝试从 `idx` 出发匹配 `gs[i]`,若能匹配成功,则整段更新 $idx = idx + gs[i].length$;否则将 `idx` 后移一位,继续尝试匹配 `gs[i]`。 代码: -```java +```Java class Solution { public boolean canChoose(int[][] gs, int[] nums) { - int n = nums.length, m = gs.length; - int cnt = 0; - for (int i = 0, j = 0; i < n && j < m;) { - if (check(gs[j], nums, i)) { - i += gs[j++].length; - cnt++; - } else { - i++; + int m = nums.length, idx = 0; + out:for (int[] info : gs) { + for (int j = idx; j + info.length <= m; j++) { + boolean ok = true; + for (int k = 0; k < info.length && ok; k++) { + if (nums[j + k] != info[k]) ok = false; + } + if (ok) { + idx = j + info.length; + continue out; + } } + return false; } - return cnt == m; - } - boolean check(int[] g, int[] nums, int i) { - int j = 0; - for (;j < g.length && i < nums.length; j++, i++) { - if (g[j] != nums[i]) return false; - } - return j == g.length; + return true; } } ``` -* 时间复杂度:$O(n * m)$ +* 时间复杂度:$O(n \times m)$ * 空间复杂度:$O(1)$ ---