diff --git "a/Index/\345\233\276\350\256\272 BFS.md" "b/Index/\345\233\276\350\256\272 BFS.md" index 8fde688e..21c3569d 100644 --- "a/Index/\345\233\276\350\256\272 BFS.md" +++ "b/Index/\345\233\276\350\256\272 BFS.md" @@ -17,6 +17,7 @@ | [1034. 边界着色](https://leetcode-cn.com/problems/coloring-a-border/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/coloring-a-border/solution/gong-shui-san-xie-tu-lun-sou-suo-zhuan-t-snvw/) | 中等 | 🤩🤩🤩🤩 | | [1036. 逃离大迷宫](https://leetcode-cn.com/problems/escape-a-large-maze/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/escape-a-large-maze/solution/gong-shui-san-xie-bfs-gei-ding-zhang-ai-8w63o/) | 困难 | 🤩🤩🤩🤩 | | [1162. 地图分析](https://leetcode-cn.com/problems/as-far-from-land-as-possible/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/as-far-from-land-as-possible/solution/gong-shui-san-xie-ru-he-shi-yong-duo-yua-vlea/) | 中等 | 🤩🤩🤩🤩 | +| [1222. 可以攻击国王的皇后](https://leetcode.cn/problems/queens-that-can-attack-the-king/) | [LeetCode 题解链接](https://leetcode.cn/problems/queens-that-can-attack-the-king/solution/gong-shui-san-xie-chang-gui-mo-ni-ti-by-hlgkx/) | 中等 | 🤩🤩🤩🤩 | | [1345. 跳跃游戏 IV](https://leetcode-cn.com/problems/jump-game-iv/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/jump-game-iv/solution/gong-shui-san-xie-noxiang-xin-ke-xue-xi-q9tb1/) | 困难 | 🤩🤩🤩🤩🤩 | | [1765. 地图中的最高点](https://leetcode-cn.com/problems/map-of-highest-peak/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/map-of-highest-peak/solution/gong-shui-san-xie-duo-yuan-bfs-yun-yong-8sw0f/) | 中等 | 🤩🤩🤩🤩 | | [2039. 网络空闲的时刻](https://leetcode-cn.com/problems/the-time-when-the-network-becomes-idle/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/the-time-when-the-network-becomes-idle/solution/by-ac_oier-5txs/) | 中等 | 🤩🤩🤩 | diff --git "a/Index/\346\236\204\351\200\240.md" "b/Index/\346\236\204\351\200\240.md" index 662d936b..13f0724a 100644 --- "a/Index/\346\236\204\351\200\240.md" +++ "b/Index/\346\236\204\351\200\240.md" @@ -10,6 +10,7 @@ | [791. 自定义字符串排序](https://leetcode.cn/problems/custom-sort-string/) | [LeetCode 题解链接](https://leetcode.cn/problems/custom-sort-string/solution/by-ac_oier-ali0/) | 中等 | 🤩🤩🤩🤩🤩 | | [899. 有序队列](https://leetcode.cn/problems/orderly-queue/) | [LeetCode 题解链接](https://leetcode.cn/problems/orderly-queue/solution/by-ac_oier-443m/) | 困难 | 🤩🤩🤩 | | [942. 增减字符串匹配](https://leetcode.cn/problems/di-string-match/) | [LeetCode 题解链接](https://leetcode.cn/problems/di-string-match/solution/by-ac_oier-pvjk/) | 简单 | 🤩🤩🤩🤩🤩 | +| [950. 按递增顺序显示卡牌](https://leetcode.cn/problems/reveal-cards-in-increasing-order/) | [LeetCode 题解链接](https://leetcode.cn/problems/reveal-cards-in-increasing-order/solution/gong-shui-san-xie-jian-dan-mo-ni-ti-by-a-nu48/) | 中等 | 🤩🤩🤩🤩🤩 | | [961. 在长度 2N 的数组中找出重复 N 次的元素](https://leetcode.cn/problems/n-repeated-element-in-size-2n-array/) | [LeetCode 题解链接](https://leetcode.cn/problems/n-repeated-element-in-size-2n-array/solution/by-ac_oier-bslq/) | 简单 | 🤩🤩🤩🤩 | | [1092. 最短公共超序列](https://leetcode.cn/problems/shortest-common-supersequence/) | [LeetCode 题解链接](https://leetcode.cn/problems/shortest-common-supersequence/solution/by-ac_oier-s346/) | 困难 | 🤩🤩🤩🤩 | | [1260. 二维网格迁移](https://leetcode.cn/problems/shift-2d-grid/) | [LeetCode 题解链接](https://leetcode.cn/problems/shift-2d-grid/solution/by-ac_oier-1blt/) | 简单 | 🤩🤩🤩🤩 | diff --git "a/Index/\346\250\241\346\213\237.md" "b/Index/\346\250\241\346\213\237.md" index 4a37779e..bb30e6a4 100644 --- "a/Index/\346\250\241\346\213\237.md" +++ "b/Index/\346\250\241\346\213\237.md" @@ -136,8 +136,10 @@ | [929. 独特的电子邮件地址](https://leetcode.cn/problems/unique-email-addresses/) | [LeetCode 题解链接](https://leetcode.cn/problems/unique-email-addresses/solution/by-ac_oier-d3zu/) | 简单 | 🤩🤩🤩 | | [944. 删列造序](https://leetcode.cn/problems/delete-columns-to-make-sorted/) | [LeetCode 题解链接](https://leetcode.cn/problems/delete-columns-to-make-sorted/solution/by-ac_oier-smoz/) | 简单 | 🤩🤩🤩 | | [946. 验证栈序列](https://leetcode.cn/problems/validate-stack-sequences/) | [LeetCode 题解链接](https://leetcode.cn/problems/validate-stack-sequences/solution/by-ac_oier-84qd/) | 中等 | 🤩🤩🤩🤩 | +| [950. 按递增顺序显示卡牌](https://leetcode.cn/problems/reveal-cards-in-increasing-order/) | [LeetCode 题解链接](https://leetcode.cn/problems/reveal-cards-in-increasing-order/solution/gong-shui-san-xie-jian-dan-mo-ni-ti-by-a-nu48/) | 中等 | 🤩🤩🤩🤩🤩 | | [953. 验证外星语词典](https://leetcode.cn/problems/verifying-an-alien-dictionary/) | [LeetCode 题解链接](https://leetcode.cn/problems/verifying-an-alien-dictionary/solution/by-ac_oier-sxf1/) | 简单 | 🤩🤩🤩🤩 | | [961. 在长度 2N 的数组中找出重复 N 次的元素](https://leetcode.cn/problems/n-repeated-element-in-size-2n-array/) | [LeetCode 题解链接](https://leetcode.cn/problems/n-repeated-element-in-size-2n-array/solution/by-ac_oier-bslq/) | 简单 | 🤩🤩🤩🤩 | +| [985. 查询后的偶数和](https://leetcode.cn/problems/sum-of-even-numbers-after-queries/) | [LeetCode 题解链接](https://leetcode.cn/problems/sum-of-even-numbers-after-queries/solution/gong-shui-san-xie-jian-dan-mo-ni-ti-by-a-lwfq/) | 中等 | 🤩🤩🤩🤩 | | [997. 找到小镇的法官](https://leetcode-cn.com/problems/find-the-town-judge/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/find-the-town-judge/solution/gong-shui-san-xie-jian-dan-chu-du-ru-du-5ms57/) | 简单 | 🤩🤩🤩🤩 | | [998. 最大二叉树 II](https://leetcode.cn/problems/maximum-binary-tree-ii/) | [LeetCode 题解链接](https://leetcode.cn/problems/maximum-binary-tree-ii/solution/by-ac_oier-v82s/) | 中等 | 🤩🤩🤩🤩 | | [1001. 网格照明](https://leetcode-cn.com/problems/grid-illumination/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/grid-illumination/solution/gong-shui-san-xie-ha-xi-biao-xian-ying-s-s48d/) | 困难 | 🤩🤩🤩🤩 | @@ -152,6 +154,7 @@ | [1184. 公交站间的距离](https://leetcode.cn/problems/distance-between-bus-stops/) | [LeetCode 题解链接](https://leetcode.cn/problems/distance-between-bus-stops/solution/by-ac_oier-fow3/) | 简单 | 🤩🤩🤩🤩 | | [1185. 一周中的第几天](https://leetcode-cn.com/problems/day-of-the-week/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/day-of-the-week/solution/gong-shui-san-xie-jian-dan-ri-qi-tong-ji-czt6/) | 简单 | 🤩🤩🤩🤩 | | [1189. “气球” 的最大数量](https://leetcode-cn.com/problems/maximum-number-of-balloons/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/maximum-number-of-balloons/solution/gong-shui-san-xie-jian-dan-mo-ni-ti-by-a-9px4/) | 简单 | 🤩🤩🤩🤩 | +| [1222. 可以攻击国王的皇后](https://leetcode.cn/problems/queens-that-can-attack-the-king/) | [LeetCode 题解链接](https://leetcode.cn/problems/queens-that-can-attack-the-king/solution/gong-shui-san-xie-chang-gui-mo-ni-ti-by-hlgkx/) | 中等 | 🤩🤩🤩🤩 | | [1224. 最大相等频率](https://leetcode.cn/problems/maximum-equal-frequency/) | [LeetCode 题解链接](https://leetcode.cn/problems/maximum-equal-frequency/solution/by-ac_oier-fviv/) | 困难 | 🤩🤩🤩🤩 | | [1252. 奇数值单元格的数目](https://leetcode.cn/problems/cells-with-odd-values-in-a-matrix/) | [LeetCode 题解链接](https://leetcode.cn/problems/cells-with-odd-values-in-a-matrix/solution/by-ac_oier-p0za/) | 简单 | 🤩🤩🤩 | | [1260. 二维网格迁移](https://leetcode.cn/problems/shift-2d-grid/) | [LeetCode 题解链接](https://leetcode.cn/problems/shift-2d-grid/solution/by-ac_oier-1blt/) | 简单 | 🤩🤩🤩🤩 | diff --git "a/Index/\347\212\266\345\216\213 DP.md" "b/Index/\347\212\266\345\216\213 DP.md" index 0796bcf0..377bb506 100644 --- "a/Index/\347\212\266\345\216\213 DP.md" +++ "b/Index/\347\212\266\345\216\213 DP.md" @@ -3,6 +3,7 @@ | [526. 优美的排列](https://leetcode-cn.com/problems/beautiful-arrangement/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/beautiful-arrangement/solution/gong-shui-san-xie-xiang-jie-liang-chong-vgsia/) | 中等 | 🤩🤩🤩🤩🤩 | | [691. 贴纸拼词](https://leetcode.cn/problems/stickers-to-spell-word/) | [LeetCode 题解链接](https://leetcode.cn/problems/stickers-to-spell-word/solution/by-ac_oier-5vv3/) | 困难 | 🤩🤩🤩🤩 | | [847. 访问所有节点的最短路径](https://leetcode-cn.com/problems/shortest-path-visiting-all-nodes/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/shortest-path-visiting-all-nodes/solution/gong-shui-san-xie-yi-ti-shuang-jie-bfs-z-6p2k/) | 困难 | 🤩🤩🤩🤩🤩 | +| [943. 最短超级串](https://leetcode.cn/problems/find-the-shortest-superstring/) | [LeetCode 题解链接](https://leetcode.cn/problems/find-the-shortest-superstring/solution/gong-shui-san-xie-zhuang-ya-dp-yun-yong-p6hlz/) | 困难 | 🤩🤩🤩🤩🤩 | | [1994. 好子集的数目](https://leetcode-cn.com/problems/the-number-of-good-subsets/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/the-number-of-good-subsets/solution/gong-shui-san-xie-zhuang-ya-dp-yun-yong-gz4w5/) | 困难 | 🤩🤩🤩🤩 | | [2044. 统计按位或能得到最大值的子集数目](https://leetcode-cn.com/problems/count-number-of-maximum-bitwise-or-subsets/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/count-number-of-maximum-bitwise-or-subsets/solution/by-ac_oier-dos6/) | 困难 | 🤩🤩🤩🤩 | diff --git "a/LeetCode/1041-1050/1041. \345\233\260\344\272\216\347\216\257\344\270\255\347\232\204\346\234\272\345\231\250\344\272\272\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1041-1050/1041. \345\233\260\344\272\216\347\216\257\344\270\255\347\232\204\346\234\272\345\231\250\344\272\272\357\274\210\344\270\255\347\255\211\357\274\211.md" new file mode 100644 index 00000000..13375b14 --- /dev/null +++ "b/LeetCode/1041-1050/1041. \345\233\260\344\272\216\347\216\257\344\270\255\347\232\204\346\234\272\345\231\250\344\272\272\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -0,0 +1,216 @@ +### 题目描述 + +这是 LeetCode 上的 **[1041. 困于环中的机器人](https://leetcode.cn/problems/robot-bounded-in-circle/solution/gong-shui-san-xie-chang-gui-mo-ni-ti-by-hgdtp/)** ,难度为 **中等**。 + +Tag : 「模拟」、「脑筋急转弯」 + + + +在无限的平面上,机器人最初位于 $(0, 0)$ 处,面朝北方。注意: + +* 北方向 是 `y` 轴的正方向。 +* 南方向 是 `y` 轴的负方向。 +* 东方向 是 `x` 轴的正方向。 +* 西方向 是 `x` 轴的负方向。 + +机器人可以接受下列三条指令之一: + +* `"G"`:直走 $1$ 个单位 +* `"L"`:左转 $90$ 度 +* `"R"`:右转 $90$ 度 + +机器人按顺序执行指令 `instructions`,并一直重复它们。 + +只有在平面中存在环使得机器人永远无法离开时,返回 `true`。否则,返回 `false`。 + +示例 1: +``` +输入:instructions = "GGLLGG" + +输出:true + +解释:机器人最初在(0,0)处,面向北方。 +“G”:移动一步。位置:(0,1)方向:北。 +“G”:移动一步。位置:(0,2).方向:北。 +“L”:逆时针旋转90度。位置:(0,2).方向:西。 +“L”:逆时针旋转90度。位置:(0,2)方向:南。 +“G”:移动一步。位置:(0,1)方向:南。 +“G”:移动一步。位置:(0,0)方向:南。 +重复指令,机器人进入循环:(0,0)——>(0,1)——>(0,2)——>(0,1)——>(0,0)。 +在此基础上,我们返回true。 +``` +示例 2: +``` +输入:instructions = "GG" + +输出:false + +解释:机器人最初在(0,0)处,面向北方。 +“G”:移动一步。位置:(0,1)方向:北。 +“G”:移动一步。位置:(0,2).方向:北。 +重复这些指示,继续朝北前进,不会进入循环。 +在此基础上,返回false。 +``` +示例 3: +``` +输入:instructions = "GL" + +输出:true + +解释:机器人最初在(0,0)处,面向北方。 +“G”:移动一步。位置:(0,1)方向:北。 +“L”:逆时针旋转90度。位置:(0,1).方向:西。 +“G”:移动一步。位置:(- 1,1)方向:西。 +“L”:逆时针旋转90度。位置:(- 1,1)方向:南。 +“G”:移动一步。位置:(- 1,0)方向:南。 +“L”:逆时针旋转90度。位置:(- 1,0)方向:东方。 +“G”:移动一步。位置:(0,0)方向:东方。 +“L”:逆时针旋转90度。位置:(0,0)方向:北。 +重复指令,机器人进入循环:(0,0)——>(0,1)——>(- 1,1)——>(- 1,0)——>(0,0)。 +在此基础上,我们返回true。 +``` + +提示: +* $1 <= instructions.length <= 100$ +* `instructions[i]` 仅包含 `'G'`, `'L'`, `'R'` + +--- + +### 模拟 + +为了方便,将 `instructions` 记为 `s`,“北西南东”四个方向分别记为“上左下右”四个逆时针方向。 + +起始位置在 $(0,0)$,方向为上,我们可以将「位置 + 方向」统称为「状态」。 + +所谓“循环”,则是指执行若干次的 `s` 后,会回到相同的状态。 + +我们可以按 `s` 执行一遍,假设执行完所在位置为 $(x, y)$,所在位置为 $k$,先根据 **位置** 分情况讨论: + +1. $(x, y)$ 为 $(0, 0)$,此时无论执行一遍后的方向为何值,必然能在若干次执行后回到起始状态。 + + 即只需要确保 `(n * k) % 4` 为 $0$ 即可,机器人会陷入循环; + +2. $(x, y)$ 不为 $(0, 0)$,再根据 **方向** 进一步分情况讨论: + + * 方向为上:每执行一遍 `s` 指令,位置变化为 $(x, y)$,方向不变。 + + 那么执行 $n$ 遍后位置为 $(n \times x, n \times y)$,其中 $n$ 为正整数,并且 $x$ 和 $y$ 不同时为 $0$,因此随着执行次数增加,位置会离 $(0, 0)$ 越来越远,机器人不会陷入循环; + + * 方向为下:每执行一遍 `s` 指令,位置变化为 $(x, y)$,方向翻转。 + + 如果再执行一遍,由于再次执行时的方向与起始方向相反,因此位置变化为 $(-x, -y)$,同时方向再次翻转(与起始方向一致)。即执行偶数次后,会回到起始状态,机器人会陷入循环; + + * 方向为左:每执行一遍 `s` 指令,位置变化为 $(x, y)$,方向为逆时针 $90$ 度。 + + 如果执行第二次,位置变化为 $(-y, x)$,方向再逆时针 $90$ 度(与起始方向相反);执行第三次,位置变化为 $(-x, -y)$,方向再逆时针 $90$ 度(与起始方向呈顺时针 $90$ 度),该次变化会和首次执行相互抵消;执行第四次,位置变化为 $(y, -x)$,方向再逆时针 $90$ 度(与起始方向相同),该次变化与第二次执行相互抵消。总的位置变化为 $(0, 0)$,同时方向与起始方向一致,机器人会陷入循环; + + * 方向为右:与「方向为左」同理,机器人会陷入循环。 + +综上,只要执行一遍 `s` 后所在位置为 $(0, 0)$ 或方向不为上,均可确保循环发生。 + +Java 代码: +```Java +class Solution { + public boolean isRobotBounded(String s) { + int x = 0, y = 0, d = 0; + int[][] dirs = new int[][]{{0,1}, {-1,0}, {0,-1}, {1,0}}; + for (char c : s.toCharArray()) { + if (c == 'G') { + x += dirs[d][0]; y += dirs[d][1]; + } else if (c == 'L') { + d = (d + 1) % 4; + } else { + d = ((d - 1) % 4 + 4) % 4; + } + } + return (x == 0 && y == 0) || d != 0; + } +} +``` +C++ 代码: +```C++ +class Solution { +public: + bool isRobotBounded(string s) { + int x = 0, y = 0, d = 0; + int dirs[4][2] = {{0, 1}, {-1, 0}, {0, -1}, {1, 0}}; + for (char c : s) { + if (c == 'G') { + x += dirs[d][0]; y += dirs[d][1]; + } else if (c == 'L') { + d = (d + 1) % 4; + } else { + d = ((d - 1) % 4 + 4) % 4; + } + } + return (x == 0 && y == 0) || d != 0; + } +}; +``` +Python 代码: +```Python +class Solution: + def isRobotBounded(self, s: str) -> bool: + x, y, d = 0, 0, 0 + dirs = [[0, 1], [-1, 0], [0, -1], [1, 0]] + for c in s: + if c == 'G': + x += dirs[d][0] + y += dirs[d][1] + elif c == 'L': + d = (d + 1) % 4 + else: + d = ((d - 1) % 4 + 4) % 4 + return (x == 0 and y == 0) or d != 0 +``` +Go 代码: +```Go +func isRobotBounded(s string) bool { + x, y, d := 0, 0, 0 + dirs := [][]int{{0, 1}, {-1, 0}, {0, -1}, {1, 0}} + for _, c := range s { + if c == 'G' { + x += dirs[d][0] + y += dirs[d][1] + } else if c == 'L' { + d = (d + 1) % 4 + } else { + d = ((d - 1) % 4 + 4) % 4 + } + } + return (x == 0 && y == 0) || d != 0 +} +``` +TypeScript 代码: +```TypeScript +function isRobotBounded(s: string): boolean { + let x = 0, y = 0, d = 0; + const dirs: number[][] = [[0, 1], [-1, 0], [0, -1], [1, 0]]; + for (const c of s) { + if (c === 'G') { + x += dirs[d][0]; + y += dirs[d][1]; + } else if (c === 'L') { + d = (d + 1) % 4; + } else { + d = ((d - 1) % 4 + 4) % 4; + } + } + return (x === 0 && y === 0) || d !== 0; +}; +``` +* 时间复杂度:$O(n)$ +* 空间复杂度:$O(1)$ + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.1041` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 + diff --git "a/LeetCode/1221-1230/1222. \345\217\257\344\273\245\346\224\273\345\207\273\345\233\275\347\216\213\347\232\204\347\232\207\345\220\216\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1221-1230/1222. \345\217\257\344\273\245\346\224\273\345\207\273\345\233\275\347\216\213\347\232\204\347\232\207\345\220\216\357\274\210\344\270\255\347\255\211\357\274\211.md" new file mode 100644 index 00000000..c22a0b3d --- /dev/null +++ "b/LeetCode/1221-1230/1222. \345\217\257\344\273\245\346\224\273\345\207\273\345\233\275\347\216\213\347\232\204\347\232\207\345\220\216\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -0,0 +1,158 @@ +### 题目描述 + +这是 LeetCode 上的 **[1222. 可以攻击国王的皇后](https://leetcode.cn/problems/queens-that-can-attack-the-king/solution/gong-shui-san-xie-chang-gui-mo-ni-ti-by-hlgkx/)** ,难度为 **中等**。 + +Tag : 「模拟」、「BFS」 + + + +在一个 `8x8` 的棋盘上,放置着若干「黑皇后」和一个「白国王」。 + +给定一个由整数坐标组成的数组 `queens`,表示黑皇后的位置;以及一对坐标 `king`,表示白国王的位置,返回所有可以攻击国王的皇后的坐标(任意顺序)。 + +示例 1: + +![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2019/10/13/untitled-diagram.jpg) + +``` +输入:queens = [[0,1],[1,0],[4,0],[0,4],[3,3],[2,4]], king = [0,0] + +输出:[[0,1],[1,0],[3,3]] + +解释: +[0,1] 的皇后可以攻击到国王,因为他们在同一行上。 +[1,0] 的皇后可以攻击到国王,因为他们在同一列上。 +[3,3] 的皇后可以攻击到国王,因为他们在同一条对角线上。 +[0,4] 的皇后无法攻击到国王,因为她被位于 [0,1] 的皇后挡住了。 +[4,0] 的皇后无法攻击到国王,因为她被位于 [1,0] 的皇后挡住了。 +[2,4] 的皇后无法攻击到国王,因为她和国王不在同一行/列/对角线上。 +``` +示例 2: + +![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2019/10/13/untitled-diagram-1.jpg) + +``` +输入:queens = [[0,0],[1,1],[2,2],[3,4],[3,5],[4,4],[4,5]], king = [3,3] + +输出:[[2,2],[3,4],[4,4]] +``` +示例 3: + +![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2019/10/13/untitled-diagram-2.jpg) + +``` +输入:queens = [[5,6],[7,7],[2,1],[0,7],[1,6],[5,1],[3,7],[0,3],[4,0],[1,2],[6,3],[5,0],[0,4],[2,2],[1,1],[6,4],[5,4],[0,0],[2,6],[4,5],[5,2],[1,4],[7,5],[2,3],[0,5],[4,2],[1,0],[2,7],[0,1],[4,6],[6,1],[0,6],[4,3],[1,7]], king = [3,4] + +输出:[[2,3],[1,4],[1,6],[3,7],[4,3],[5,4],[4,5]] +``` + +提示: +* $1 <= queens.length <= 63$ +* $queens[i].length == 2$ +* $0 <= queens[i][j] < 8$ +* $king.length == 2$ +* $0 <= king[0], king[1] < 8$ +* 一个棋盘格上最多只能放置一枚棋子。 + +--- + +### 模拟 + +创建一个二维数组 `dirs` 来表示八个方向的坐标偏移,同时使用变量 `step` 来表示从国王位置出发的步数。 + +在每个方向 `i` 上,通过 `step` 步可以到达的坐标为 $(x + dirs[i][0] \times step, y + dirs[i][1] \times step)$。 + +模拟过程中,我们可使用布尔数组 `checked` 来记录已处理的方向,当我们遇到皇后或越过棋盘时,可标记该方向已处理。 + +Java 代码: +```Java +class Solution { + int[][] dirs = new int[][]{{1,0},{0,1},{0,-1},{-1,0},{1,1},{-1,-1},{1,-1},{-1,1}}; + public List> queensAttacktheKing(int[][] qs, int[] k) { + boolean[][] vis = new boolean[10][10]; + for (int[] q : qs) vis[q[0]][q[1]] = true; + int x = k[0], y = k[1], step = 1; + List> ans = new ArrayList<>(); + boolean[] checked = new boolean[8]; + while (step <= 8) { + for (int i = 0; i < 8; i++) { + if (checked[i]) continue; + int nx = x + dirs[i][0] * step, ny = y + dirs[i][1] * step; + if (nx < 0 || nx >= 8 || ny < 0 || ny >= 8) { + checked[i] = true; + } else { + if (!vis[nx][ny]) continue; + add(ans, nx, ny); + checked[i] = true; + } + } + step++; + } + return ans; + } + void add(List> ans, int x, int y) { + List list = new ArrayList<>(); + list.add(x); list.add(y); + ans.add(list); + } +} +``` +* 时间复杂度:$O(C)$,其中 $C = 8 \times 8$ 为棋盘总大小 +* 空间复杂度:$O(C)$,其中 $C = 8 \times 8$ 为棋盘总大小 + +--- + +### BFS + +上述模拟过程也可以使用 `BFS` 方式进行。 + +相比于直接模拟,`BFS` 无须使用额外变量记录处理过的方向以及当前位置与国王的距离。 + +Java 代码: + + +```Java +class Solution { + int[][] dirs = new int[][]{{1,0},{0,1},{0,-1},{-1,0},{1,1},{-1,-1},{1,-1},{-1,1}}; + public List> queensAttacktheKing(int[][] qs, int[] k) { + boolean[][] vis = new boolean[10][10]; + for (int[] q : qs) vis[q[0]][q[1]] = true; + Deque d = new ArrayDeque<>(); + for (int i = 0; i < 8; i++) { + int x = k[0] + dirs[i][0], y = k[1] + dirs[i][1]; + if (x < 0 || x >= 8 || y < 0 || y >= 8) continue; + d.addLast(new int[]{x, y, i}); + } + List> ans = new ArrayList<>(); + while (!d.isEmpty()) { + int[] info = d.pollFirst(); + int x = info[0], y = info[1], p = info[2]; + if (vis[x][y]) { + List list = new ArrayList<>(); + list.add(x); list.add(y); + ans.add(list); + } else { + int nx = x + dirs[p][0], ny = y + dirs[p][1]; + if (nx < 0 || nx >= 8 || ny < 0 || ny >= 8) continue; + d.addLast(new int[]{nx, ny, p}); + } + } + return ans; + } +} +``` +* 时间复杂度:$O(C)$,其中 $C = 4 \times 8$ 为四条线的总步数 +* 空间复杂度:$O(C)$,其中 $C = 8 \times 8$ 为棋盘总大小 + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.1222` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 + diff --git "a/LeetCode/1251-1260/1253. \351\207\215\346\236\204 2 \350\241\214\344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1251-1260/1253. \351\207\215\346\236\204 2 \350\241\214\344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\357\274\210\344\270\255\347\255\211\357\274\211.md" new file mode 100644 index 00000000..8eca5495 --- /dev/null +++ "b/LeetCode/1251-1260/1253. \351\207\215\346\236\204 2 \350\241\214\344\272\214\350\277\233\345\210\266\347\237\251\351\230\265\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -0,0 +1,112 @@ +### 题目描述 + +这是 LeetCode 上的 **[1253. 重构 2 行二进制矩阵]()** ,难度为 **中等**。 + +Tag : 「模拟」、「贪心」、「构造」 + + + +给你一个 `2` 行 `n` 列的二进制数组: + +* 矩阵是一个二进制矩阵,这意味着矩阵中的每个元素不是 0 就是 1。 +* 第 `0` 行的元素之和为 `upper`。 +* 第 `1` 行的元素之和为 `lower`。 +* 第 `i` 列(从 `0` 开始编号)的元素之和为 `colsum[i]`,`colsum` 是一个长度为 `n` 的整数数组。 + +你需要利用 `upper`,`lower` 和 `colsum` 来重构这个矩阵,并以二维整数数组的形式返回它。 + +如果有多个不同的答案,那么任意一个都可以通过本题。 + +如果不存在符合要求的答案,就请返回一个空的二维数组。 + +示例 1: +``` +输入:upper = 2, lower = 1, colsum = [1,1,1] + +输出:[[1,1,0],[0,0,1]] + +解释:[[1,0,1],[0,1,0]] 和 [[0,1,1],[1,0,0]] 也是正确答案。 +``` +示例 2: +``` +输入:upper = 2, lower = 3, colsum = [2,2,1,1] + +输出:[] +``` +示例 3: +``` +输入:upper = 5, lower = 5, colsum = [2,1,2,0,1,0,1,2,0,1] + +输出:[[1,1,1,0,1,0,0,1,0,0],[1,0,1,0,0,0,1,1,0,1]] +``` + +提示: +* $1 <= colsum.length <= 10^5$ +* $0 <= upper, lower <= colsum.length$ +* $0 <= colsum[i] <= 2$ + +--- + +### 贪心 + 构造 + +创建数组 `a` 和 `b` 分别代表目标二进制矩阵的第 `0` 行和第 `1` 行。 + +从前往后处理 `colsum`,复用 `upper` 和 `lower` 分别代表两行剩余 $1$ 的个数。 + +根据当前的 $colsum[i]$ 进行分情况讨论: + +* 若 $colsum[i] = 0$,只有一种情况,当前位置两行均为 $0$ +* 若 $colsum[i] = 2$,只有一种情况,当前位置两行均为 $1$ +* 若 $colsum[i] = 1$,选剩余 `1` 个数较大的行,填入 $1$,另外行则填入 $0$ + +若处理完 `colsum` 后,两行剩余 $1$ 个数恰好均为 $0$,说明构造出了合法方案。 + +容易证明:**不存在某个决策回合中,必须先填入剩余个数少的一方,才能顺利构造。**可用反证法进行证明,若存在某个回合必须填入剩余个数少的一方(假设该回合上填 `1` 下填 `0`),必然能够找到同为 $colsum[j] = 1$ 的回合进行交换,同时不影响合法性(上下行的总和不变,同时 $colsum[i] = colsum[j] = 1$)。 + +代码: + +```Java +class Solution { + public List> reconstructMatrix(int upper, int lower, int[] colsum) { + int n = colsum.length; + List> ans = new ArrayList<>(); + List a = new ArrayList<>(), b = new ArrayList<>(); + for (int i = 0; i < n; i++) { + int m = colsum[i]; + if (m == 0) { + a.add(0); b.add(0); + } else if (m == 2) { + upper--; lower--; + a.add(1); b.add(1); + } else { + if (upper >= lower) { + upper--; + a.add(1); b.add(0); + } else { + lower--; + a.add(0); b.add(1); + } + } + } + if (upper == 0 && lower == 0) { + ans.add(a); ans.add(b); + } + return ans; + } +} +``` +* 时间复杂度:$O(C \times n)$,其中 $C = 2$ 代表行数 +* 空间复杂度:$O(C \times n)$ + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.1253` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 + diff --git "a/LeetCode/1991-2000/1994. \345\245\275\345\255\220\351\233\206\347\232\204\346\225\260\347\233\256\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/1991-2000/1994. \345\245\275\345\255\220\351\233\206\347\232\204\346\225\260\347\233\256\357\274\210\345\233\260\351\232\276\357\274\211.md" index d4916913..7229088a 100644 --- "a/LeetCode/1991-2000/1994. \345\245\275\345\255\220\351\233\206\347\232\204\346\225\260\347\233\256\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/1991-2000/1994. \345\245\275\345\255\220\351\233\206\347\232\204\346\225\260\347\233\256\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -6,7 +6,7 @@ Tag : 「状压 DP」 -给你一个整数数组 nums 。如果 nums 的一个子集中,所有元素的乘积可以表示为一个或多个 互不相同的质数 的乘积,那么我们称它为 好子集 。 +给你一个整数数组 `nums`。如果 `nums` 的一个子集中,所有元素的乘积可以表示为一个或多个 互不相同的质数 的乘积,那么我们称它为 好子集 。 * 比方说,如果 `nums = [1, 2, 3, 4]` : * `[2, 3]` ,`[1, 2, 3]` 和 `[1, 3]` 是 好 子集,乘积分别为 `6 = 2*3` ,`6 = 2*3` 和 `3 = 3` 。 @@ -51,8 +51,6 @@ Tag : 「状压 DP」 ### 状压 DP -> 今天出了点状况,只能到公司后再写题解了 ... - 该问题属于 NP 完全问题,注定不存在多项式解决方案,只能通过「爆搜 + 剪枝」或「状压 DP」来求解。 对子集的乘积进行质数分解,等价于对子集每一位数进行质数分解。 @@ -61,13 +59,13 @@ Tag : 「状压 DP」 同时,题目规定数值相同,下标不同均视为不同方案,因此我们可以先使用数组 $cnts$ 统计在 $nums$ 中每个数的出现次数,$cnts[val] = x$ 含义为数值 $val$ 在 $nums$ 中的出现次数为 $x$ 次。 -**使用的数有限(共 $10$ 个),并且使用到的数最多出现一次,容易想到使用「状压 DP」来求解:我们使用一个二进制数来表示好子集乘积最终能拆解成哪些质数,如果拆解结果中包含 $p[i]$,对应的二进制表示中的第 $i$ 位则为 $1$,否则为 $0$。** +使用的数有限(共 $10$ 个),并且使用到的数最多出现一次,容易想到使用「状压 DP」来求解:我们使用一个二进制数来表示好子集乘积最终能拆解成哪些质数,如果拆解结果中包含 $p[i]$,对应的二进制表示中的第 $i$ 位则为 $1$,否则为 $0$。 **定义 $f[state]$ 为当前子集乘积拆解结果的用到的质数为 $state$ 时的方案数,$state$ 为一个长度 $10$ 的二进制数,若 $state$ 中的第 $k$ 位二进制表示为 $1$,代表数值 $p[k]$ 在拆解结果中出现过;若第 $k$ 位二进制表示为 $0$ 代表 $p[k]$ 在拆解结果中没出现过。** 我们有起始化条件:空集,即 $f[0] = 1$。 -不失一般性考虑 $f[s]$ 该如何计算:从前往后考虑每个数值(范围 $[2, 30]$ 的数,$1$ 添加与否不对好子集产生影响,最后讨论)是否可以加入到子集中,一个数值 $t$ 能够添加到子集中的充要条件为题目给定的条件:**该数不会被相同的质数相乘表示。** +不失一般性考虑 $f[s]$ 该如何计算:从前往后考虑每个数值(范围 $[2, 30]$ 的数,$1$ 添加与否不对好子集产生影响,最后讨论)是否可以加入到子集中,一个数值 $t$ 能够添加到子集中的充要条件为题目给定的条件:**该数不会被相同的质数相乘表示**。 如果一个数值 $t$ 能够添加到好子集中,我们通过「试除法」将其分解为 $p$ 中的多个质数,并使用二进制数 $cur$ 来表示用到了 $p$ 中的哪些质数,然后需要判断 $t$ 能够添加到那些子集中,其实就是枚举与 $cur$ 无交集的状态 $prev$,最终的 $f[s]$ 为「所有合法的 $prev$ 的状态数 $f[prev]$」与「数值 $t$ 的出现次数 $cnts[t]$ 」的乘积之和。 @@ -75,7 +73,7 @@ Tag : 「状压 DP」 由「质数 $p$ 组成的好子集方案数」为 $ans = \sum_{state' = 1}^{{1024}} f[state']$,其中 $state'$ 对应一个合法的好子集方案。 -在此基础上,再考虑数值 $1$ 对答案的影响:**在每个合法的 $state'$ 前提下,增加若干个 $1$ 并不影响子集乘积(即好子集增加 $1$ 后仍为好子集),因此每个合法子集 $state'$ 可以对应出 $2^{cnts[1]}$ 个具体方案(代表每个 $1$ 即可以选,也可以不选)。** +在此基础上,再考虑数值 $1$ 对答案的影响:**在每个合法的 $state'$ 前提下,增加若干个 $1$ 并不影响子集乘积(即好子集增加 $1$ 后仍为好子集),因此每个合法子集 $state'$ 可以对应出 $2^{cnts[1]}$ 个具体方案(代表每个 $1$ 即可以选,也可以不选)**。 代码: ```Java @@ -121,7 +119,7 @@ class Solution { } } ``` -* 时间复杂度:预处理每个数值的出现次数复杂度为 $O(n)$;令数值范围 $C = 30$,状态数为 $M = 1024$,DP 部分复杂度为 $O(C * M)$。整体复杂度为 $O(n + C * M)$ +* 时间复杂度:预处理每个数值的出现次数复杂度为 $O(n)$;令数值范围 $C = 30$,状态数为 $M = 1024$,DP 部分复杂度为 $O(C \times M)$。整体复杂度为 $O(n + C \times M)$ * 空间复杂度:$O(C + M)$ --- @@ -178,8 +176,8 @@ class Solution { } } ``` -* 时间复杂度:预处理每个数值的出现次数复杂度为 $O(n)$;令数值范围 $C = 30$,状态数为 $M = 1024$,DP 部分复杂度为 $O(C * M)$。整体复杂度为 $O(n + C * M)$ -* 空间复杂度:$O(C * M)$ +* 时间复杂度:预处理每个数值的出现次数复杂度为 $O(n)$;令数值范围 $C = 30$,状态数为 $M = 1024$,DP 部分复杂度为 $O(C \times M)$。整体复杂度为 $O(n + C \times M)$ +* 空间复杂度:$O(C \times M)$ --- diff --git "a/LeetCode/281-290/284. \351\241\266\347\253\257\350\277\255\344\273\243\345\231\250\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/281-290/284. \351\241\266\347\253\257\350\277\255\344\273\243\345\231\250\357\274\210\344\270\255\347\255\211\357\274\211.md" index 8977fe82..a5acaf1b 100644 --- "a/LeetCode/281-290/284. \351\241\266\347\253\257\350\277\255\344\273\243\345\231\250\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/281-290/284. \351\241\266\347\253\257\350\277\255\344\273\243\345\231\250\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -4,6 +4,8 @@ Tag : 「数据结构」、「模拟」 + + 请你设计一个迭代器,除了支持 `hasNext` 和 `next` 操作外,还支持 `peek` 操作。 实现 `PeekingIterator` 类: @@ -31,10 +33,10 @@ peekingIterator.hasNext(); // 返回 False ``` 提示: -* 1 <= nums.length <= 1000 -* 1 <= nums[i] <= 1000 -* 对 next 和 peek 的调用均有效 -* next、hasNext 和 peek 最多调用  1000 次 +* $1 <= nums.length <= 1000$ +* $1 <= nums[i] <= 1000$ +* 对 `next` 和 `peek` 的调用均有效 +* `next`、`hasNext` 和 `peek` 最多调用  $1000$ 次 **进阶:你将如何拓展你的设计?使之变得通用化,从而适应所有的类型,而不只是整数型?** diff --git "a/LeetCode/521-530/523. \350\277\236\347\273\255\347\232\204\345\255\220\346\225\260\347\273\204\345\222\214\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/521-530/523. \350\277\236\347\273\255\347\232\204\345\255\220\346\225\260\347\273\204\345\222\214\357\274\210\344\270\255\347\255\211\357\274\211.md" index c99b46c5..339d336d 100644 --- "a/LeetCode/521-530/523. \350\277\236\347\273\255\347\232\204\345\255\220\346\225\260\347\273\204\345\222\214\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/521-530/523. \350\277\236\347\273\255\347\232\204\345\255\220\346\225\260\347\273\204\345\222\214\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -7,45 +7,50 @@ Tag : 「前缀和」 -给你一个整数数组 nums 和一个整数 k ,编写一个函数来判断该数组是否含有同时满足下述条件的连续子数组: +给你一个整数数组 `nums` 和一个整数 `k` ,编写一个函数来判断该数组是否含有同时满足下述条件的连续子数组: -* 子数组大小 至少为 2 ,且 -* 子数组元素总和为 k 的倍数。 +* 子数组大小至少为 `2` ,且 +* 子数组元素总和为 `k` 的倍数。 -如果存在,返回 true ;否则,返回 false 。 +如果存在,返回 `true`;否则,返回 `false`。 -如果存在一个整数 n ,令整数 x 符合 x = n * k ,则称 x 是 k 的一个倍数。 +如果存在一个整数 `n` ,令整数 `x` 符合 `x = n * k` ,则称 `x` 是 `k` 的一个倍数。 示例 1: ``` 输入:nums = [23,2,4,6,7], k = 6 + 输出:true + 解释:[2,4] 是一个大小为 2 的子数组,并且和为 6 。 ``` 示例 2: ``` 输入:nums = [23,2,6,4,7], k = 6 + 输出:true + 解释:[23, 2, 6, 4, 7] 是大小为 5 的子数组,并且和为 42 。 42 是 6 的倍数,因为 42 = 7 * 6 且 7 是一个整数。 ``` 示例 3: ``` 输入:nums = [23,2,6,4,7], k = 13 + 输出:false ``` 提示: -* 1 <= nums.length <= $10^5$ -* 0 <= nums[i] <= $10^9$ -* 0 <= sum(nums[i]) <= $2^{31}$ - 1 -* 1 <= k <= $2^{31}$ - 1 +* $1 <= nums.length <= 10^5$ +* $0 <= nums[i] <= 10^9$ +* $0 <= sum(nums[i]) <= 2^{31} - 1$ +* $1 <= k <= 2^{31} - 1$ --- ### 基本分析 -这是一道很经典的前缀和题目,类似的原题也在蓝桥杯出现过,坐标在 [K 倍区间](http://lx.lanqiao.cn/problem.page?gpid=T444)。 +这是一道很经典的前缀和题目,类似的原题也在蓝桥杯出现过,坐标在 [K 倍区间](http://lx.lanqiao.cn/problem.page?gpid=T444) http://lx.lanqiao.cn/problem.page?gpid=T444。 本题与那道题不同在于: diff --git "a/LeetCode/61-70/65. \346\234\211\346\225\210\346\225\260\345\255\227\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/61-70/65. \346\234\211\346\225\210\346\225\260\345\255\227\357\274\210\345\233\260\351\232\276\357\274\211.md" index a10eeb5e..e9edc1ab 100644 --- "a/LeetCode/61-70/65. \346\234\211\346\225\210\346\225\260\345\255\227\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/61-70/65. \346\234\211\346\225\210\346\225\260\345\255\227\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -9,19 +9,19 @@ Tag : 「模拟」 有效数字(按顺序)可以分成以下几个部分: 1. 一个 小数 或者 整数 -2. (可选)一个 'e' 或 'E' ,后面跟着一个 整数 +2. (可选)一个 `'e'` 或 `'E'` ,后面跟着一个 整数 小数(按顺序)可以分成以下几个部分: -1. (可选)一个符号字符('+' 或 '-') +1. (可选)一个符号字符(`'+'` 或 `'-'`) 2. 下述格式之一: - 1. 至少一位数字,后面跟着一个点 '.' - 2. 至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字 - 3. 一个点 '.' ,后面跟着至少一位数字 + 1. 至少一位数字,后面跟着一个点 `'.'` + 2. 至少一位数字,后面跟着一个点 `'.'` ,后面再跟着至少一位数字 + 3. 一个点 `'.'` ,后面跟着至少一位数字 整数(按顺序)可以分成以下几个部分: -1. (可选)一个符号字符('+' 或 '-') +1. (可选)一个符号字符(`'+'` 或 `'-'`) 2. 至少一位数字 部分有效数字列举如下: @@ -32,33 +32,37 @@ Tag : 「模拟」 * `["abc", "1a", "1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"]` -给你一个字符串 s ,如果 s 是一个 有效数字 ,请返回 true 。 +给你一个字符串 `s`,如果 `s` 是一个 有效数字 ,请返回 `true`。 示例 1: ``` 输入:s = "0" + 输出:true ``` 示例 2: ``` 输入:s = "e" + 输出:false ``` 示例 3: ``` 输入:s = "." + 输出:false ``` 示例 4: ``` 输入:s = ".1" + 输出:true ``` 提示: -* 1 <= s.length <= 20 -* s 仅含英文字母(大写和小写),数字(0-9),加号 '+' ,减号 '-' ,或者点 '.' 。 +* $1 <= s.length <= 20$ +* `s` 仅含英文字母(大写和小写),数字(`0-9`),加号 `'+'` ,减号 `'-'` ,或者点 `'.'` 。 --- diff --git "a/LeetCode/81-90/90. \345\255\220\351\233\206 II\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/81-90/90. \345\255\220\351\233\206 II\357\274\210\344\270\255\347\255\211\357\274\211.md" index 2a5545a4..760946f9 100644 --- "a/LeetCode/81-90/90. \345\255\220\351\233\206 II\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/81-90/90. \345\255\220\351\233\206 II\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,12 +6,10 @@ Tag : 「位运算」、「回溯算法」、「状态压缩」、「DFS」 -给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。 +给你一个整数数组 `nums`,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。 解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。 - - 示例 1: ``` 输入:nums = [1,2,2] @@ -26,20 +24,19 @@ Tag : 「位运算」、「回溯算法」、「状态压缩」、「DFS」 ``` 提示: -* 1 <= nums.length <= 10 -* -10 <= nums[i] <= 10 +* $1 <= nums.length <= 10$ +* $-10 <= nums[i] <= 10$ --- ### 回溯解法(Set) -由于是求所有的方案,而且数据范围只有 10,可以直接用爆搜来做。 +由于是求所有的方案,而且数据范围只有 $10$,可以直接用爆搜来做。 -同时由于答案中不能包含相同的方案,因此我们可以先对原数组进行排序,从而确保所有爆搜出来的方案,都具有单调性,然后配合 Set 进行去重。 +同时由于答案中不能包含相同的方案,因此我们可以先对原数组进行排序,从而确保所有爆搜出来的方案,都具有单调性,然后配合 `Set` 进行去重。 代码: - -```java [] +```Java class Solution { public List> subsetsWithDup(int[] nums) { Arrays.sort(nums); @@ -72,20 +69,18 @@ class Solution { } } ``` -* 时间复杂度:排序复杂度为 $O(n\log{n})$,爆搜复杂度为 $(2^n)$,每个方案通过深拷贝存入答案,复杂度为 $O(n)$。整体复杂度为 $(n * 2^n)$ -* 空间复杂度:总共有 $2^n$ 个方案,每个方案最多占用 $O(n)$ 空间,整体复杂度为 $(n * 2^n)$ +* 时间复杂度:排序复杂度为 $O(n\log{n})$,爆搜复杂度为 $(2^n)$,每个方案通过深拷贝存入答案,复杂度为 $O(n)$。整体复杂度为 $(n \times 2^n)$ +* 空间复杂度:总共有 $2^n$ 个方案,每个方案最多占用 $O(n)$ 空间,整体复杂度为 $(n \times 2^n)$ -*** +--- ### 回溯解法 -![image.png](https://pic.leetcode-cn.com/1617157137-frVFuK-image.png) +我们知道使用 `Set` 虽然是 $O(1)$ 操作,但是只是均摊 $O(1)$。 -我们知道使用 Set 虽然是 $O(1)$ 操作,但是只是均摊 $O(1)$。 +因此我们来考虑不使用 `Set` 的做法。 -因此我们来考虑不使用 Set 的做法。 - -我们使用 Set 的目的是为了去重,那什么时候会导致的重复呢? +我们使用 `Set` 的目的是为了去重,那什么时候会导致的重复呢? **其实就是相同的元素,不同的决策方案对应同样的结果。** @@ -98,8 +93,7 @@ class Solution { **也就是说,将决策方案从「某个下标是否被选择」修改为「相同的数值被选择的个数」。这样肯定不会出现重复,因为 [1,1,1] 不会因为只选择第一个和只选择第三个产生两个 [1] 的方案,只会因为 1 被选择一次,产生一个 [1] 的方案。** 代码: - -```java +```Java class Solution { public List> subsetsWithDup(int[] nums) { Arrays.sort(nums); @@ -144,20 +138,19 @@ class Solution { } } ``` -* 时间复杂度:排序复杂度为 $O(n\log{n})$,爆搜复杂度为 $(2^n)$,每个方案通过深拷贝存入答案,复杂度为 $O(n)$。整体复杂度为 $(n * 2^n)$ -* 空间复杂度:总共有 $2^n$ 个方案,每个方案最多占用 $O(n)$ 空间,整体复杂度为 $(n * 2^n)$ +* 时间复杂度:排序复杂度为 $O(n\log{n})$,爆搜复杂度为 $(2^n)$,每个方案通过深拷贝存入答案,复杂度为 $O(n)$。整体复杂度为 $(n \times 2^n)$ +* 空间复杂度:总共有 $2^n$ 个方案,每个方案最多占用 $O(n)$ 空间,整体复杂度为 $(n \times 2^n)$ -*** +--- -### 状态压缩解法(Set) +### 状态压缩(Set) -由于长度只有 10,我们可以使用一个 int 的后 10 位来代表每位数组成员是否被选择。 +由于长度只有 10,我们可以使用一个 `int` 的后 $10$ 位来代表每位数组成员是否被选择。 -同样,我们也需要先对原数组进行排序,再配合 Set 来进行去重。 +同样,我们也需要先对原数组进行排序,再配合 `Set` 来进行去重。 代码: - -```java [] +```Java class Solution { public List> subsetsWithDup(int[] nums) { Arrays.sort(nums); @@ -181,8 +174,8 @@ class Solution { } } ``` -* 时间复杂度:排序复杂度为 $O(n\log{n})$,爆搜复杂度为 $(2^n)$,每个方案通过深拷贝存入答案,复杂度为 $O(n)$。整体复杂度为 $(n * 2^n)$ -* 空间复杂度:总共有 $2^n$ 个方案,每个方案最多占用 $O(n)$ 空间,整体复杂度为 $(n * 2^n)$ +* 时间复杂度:排序复杂度为 $O(n\log{n})$,爆搜复杂度为 $(2^n)$,每个方案通过深拷贝存入答案,复杂度为 $O(n)$。整体复杂度为 $(n \times 2^n)$ +* 空间复杂度:总共有 $2^n$ 个方案,每个方案最多占用 $O(n)$ 空间,整体复杂度为 $(n \times 2^n)$ --- diff --git "a/LeetCode/941-950/943. \346\234\200\347\237\255\350\266\205\347\272\247\344\270\262\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/941-950/943. \346\234\200\347\237\255\350\266\205\347\272\247\344\270\262\357\274\210\345\233\260\351\232\276\357\274\211.md" new file mode 100644 index 00000000..f3abbf97 --- /dev/null +++ "b/LeetCode/941-950/943. \346\234\200\347\237\255\350\266\205\347\272\247\344\270\262\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -0,0 +1,285 @@ +### 题目描述 + +这是 LeetCode 上的 **[943. 最短超级串](https://leetcode.cn/problems/find-the-shortest-superstring/solution/gong-shui-san-xie-zhuang-ya-dp-yun-yong-p6hlz/)** ,难度为 **困难**。 + +Tag : 「状压 DP」、「位运算」 + + + +给定一个字符串数组 `words`,找到以 `words` 中每个字符串作为子字符串的最短字符串。如果有多个有效最短字符串满足题目条件,返回其中 任意一个 即可。 + +我们可以假设 `words` 中没有字符串是 `words` 中另一个字符串的子字符串。 + +示例 1: +``` +输入:words = ["alex","loves","leetcode"] + +输出:"alexlovesleetcode" + +解释:"alex","loves","leetcode" 的所有排列都会被接受。 +``` +示例 2: +``` +输入:words = ["catg","ctaagt","gcta","ttca","atgcatc"] + +输出:"gctaagttcatgcatc" +``` + +提示: +* $1 <= words.length <= 12$ +* $1 <= words[i].length <= 20$ +* `words[i]` 由小写英文字母组成 +* `words` 中的所有字符串互不相同 + +--- + +### 状压 DP + +为了方便,将 `words` 记为 `ws`。 + +预处理二维数组 `g` 来表示字符串 `ws[i]` 和 `ws[j]` 的重叠部分的长度:若 `g[i][j] = len` 代表字符串 `ws[i]` 长度为 `len` 的后缀与字符串 `ws[j]` 长度为 `len` 的前缀相同。 + +另外用一个二进制数 `status` 来代表当前超级串 `ans` 对 `ws` 的使用(覆盖)情况:**若 `status` 的第 `i` 位为 `1` 代表字符串 `ws[i]` 已被使用(即 `ws[i]` 已是 `ans` 的子串),若 `status` 的第 `i` 位为 `0` 代表 `ws[i]` 未被使用。** + +我们知道,当所有的 $g[i][j] = 0$ 时,代表所有拼接方式长度均为 $\sum_{i = 0}^{n - 1}ws[i].length$,即不能通过产生重叠部分来缩短超级串的长度。 + +因此,**最小化超级串 `ans` 的长度等价于最大化重叠部分的长度**。 + +定义 $f[s][i]$ 代表当前状态为 `s` 且当前最后一个使用到的字符串为 `ws[i]` (当前超级串 `ans` 的结尾部分为 `ws[i]`)时的最大重合长度。 + +最终超级串的长度为所有字符串的总长度 $\sum_{i = 0}^{n - 1}ws[i].length$ 减去最大重合长度 $\max(f[2^n - 1][i])$。 + +不失一般性考虑 $f[s][i]$ 可用于更新哪些状态,我们可枚举接在字符串 `ws[i]` 后面的字符串 `ws[j]` 为何值: + +1. 由于每个字符串只能使用一次,转移需要满足 `s` 的第 `i` 位为 $1$,`s` 的第 `j` 位为 $0$ 的前提条件,含义为 `ws[i]` 已被使用,而 `ws[j]` 未被使用 +2. 满足前提条件 $1$,代表 `ws[j]` 可接在 `ws[i]` 后面,此时有状态转移方程: + $$ + f[s | (1 << j)][j] = f[s][i] + g[i][j] + $$ + +接下来,考虑如何构建具体方案。 + +**使用二维数组 $p[s][i]$ 记录每个状态是由哪个前驱转移而来**:若有 $p[s][i] = j$,代表取得最大重叠长度过程中,字符串 `ws[j]` 接在 `ws[i]` 后面。 + +我们从后往前对 `ans` 进行构造,若 `ans = ws[0] + ws[1] + ... + ws[k - 1] + ws[k]`,我们是先找 `ws[k]`,再通过 `ws[k]` 找 `ws[k - 1]`,直到将整个 `ans` 构建出来。 + +构造过程中使用变量解释如下: + +* `ans` 为具体的超级串 +* `status` 代表当前还有哪些字符串待拼接到,初始化为 $2^n - 1$,代表还没有任何字符串拼接到 `ans` 中 +* `idx` 代表当前处理到的字符串下标,初始化通过遍历所有的 $f[2^n - 1][i]$ 找到合适的 $i$ 作为 `idx` +* `last` 代表前一个处理到字符串下标,初始化为 `-1` + +一些细节:当 `last` 不为初始值 `-1` 时,需要跳过 `ws[idx]` 与 `ws[last]` 的重复部分进行拼接。 + +Java 代码: +```Java +class Solution { + public String shortestSuperstring(String[] ws) { + int n = ws.length, mask = 1 << n; + int[][] g = new int[n][n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + String a = ws[i], b = ws[j]; + int l1 = a.length(), l2 = b.length(), len = Math.min(l1, l2); + for (int k = len; k >= 1; k--) { + if (a.substring(l1 - k).equals(b.substring(0, k))) { + g[i][j] = k; + break; + } + } + } + } + int[][] f = new int[mask][n], p = new int[mask][n]; + for (int s = 0; s < mask; s++) { + for (int i = 0; i < n; i++) { + if (((s >> i) & 1) == 0) continue; + for (int j = 0; j < n; j++) { + if (((s >> j) & 1) == 1) continue; + if (f[s | (1 << j)][j] <= f[s][i] + g[i][j]) { + f[s | (1 << j)][j] = f[s][i] + g[i][j]; + p[s | (1 << j)][j] = i; + } + } + } + } + int max = f[mask - 1][0], idx = 0, last = -1, status = mask - 1; + for (int i = 1; i < n; i++) { + if (max < f[mask - 1][i]) { + max = f[mask - 1][i]; + idx = i; + } + } + String ans = ""; + while (status != 0) { + if (last == -1) ans = ws[idx]; + else ans = ws[idx].substring(0, ws[idx].length() - g[idx][last]) + ans; + last = idx; + idx = p[status][idx]; + status ^= (1 << last); + } + return ans; + } +} +``` +Python 代码: +```Python +class Solution: + def shortestSuperstring(self, ws: List[str]) -> str: + n, mask = len(ws), 1 << len(ws) + g = [[0 for _ in range(n)] for _ in range(n)] + for i in range(n): + for j in range(n): + a, b = ws[i], ws[j] + l1, l2 = len(a), len(b) + length = min(l1, l2) + for k in range(length, 0, -1): + if a[l1 - k:] == b[:k]: + g[i][j] = k + break + f = [[0 for _ in range(n)] for _ in range(mask)] + p = [[0 for _ in range(n)] for _ in range(mask)] + for s in range(mask): + for i in range(n): + if (s >> i) & 1 == 0: + continue + for j in range(n): + if (s >> j) & 1 == 1: + continue + if f[s | (1 << j)][j] <= f[s][i] + g[i][j]: + f[s | (1 << j)][j] = f[s][i] + g[i][j] + p[s | (1 << j)][j] = i + + max_val = f[mask - 1][0] + idx, last, status = 0, -1, mask - 1 + for i in range(1, n): + if max_val < f[mask - 1][i]: + max_val = f[mask - 1][i] + idx = i + ans = "" + while status != 0: + if last == -1: + ans = ws[idx] + else: + ans = ws[idx][:len(ws[idx]) - g[idx][last]] + ans + last = idx + idx = p[status][idx] + status ^= 1 << last + return ans +``` +C++ 代码: +```C++ +class Solution { +public: + string shortestSuperstring(vector& ws) { + int n = ws.size(), mask = 1 << n; + vector> g(n, vector(n, 0)); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + string a = ws[i], b = ws[j]; + int l1 = a.length(), l2 = b.length(), len = min(l1, l2); + for (int k = len; k >= 1; k--) { + if (a.substr(l1 - k) == b.substr(0, k)) { + g[i][j] = k; + break; + } + } + } + } + vector> f(mask, vector(n, 0)), p(mask, vector(n, 0)); + for (int s = 0; s < mask; s++) { + for (int i = 0; i < n; i++) { + if (((s >> i) & 1) == 0) continue; + for (int j = 0; j < n; j++) { + if (((s >> j) & 1) == 1) continue; + if (f[s | (1 << j)][j] <= f[s][i] + g[i][j]) { + f[s | (1 << j)][j] = f[s][i] + g[i][j]; + p[s | (1 << j)][j] = i; + } + } + } + } + int max = f[mask - 1][0], idx = 0, last = -1, status = mask - 1; + for (int i = 1; i < n; i++) { + if (max < f[mask - 1][i]) { + max = f[mask - 1][i]; + idx = i; + } + } + string ans = ""; + while (status != 0) { + if (last == -1) ans = ws[idx]; + else ans = ws[idx].substr(0, ws[idx].length() - g[idx][last]) + ans; + last = idx; + idx = p[status][idx]; + status ^= (1 << last); + } + return ans; + } +}; +``` +TypeScript 代码: +```TypeScript +function shortestSuperstring(ws: string[]): string { + const n = ws.length, mask = 1 << n; + const g = new Array(n).fill(0).map(() => new Array(n).fill(0)); + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + const a = ws[i], b = ws[j]; + const l1 = a.length, l2 = b.length; + const len = Math.min(l1, l2); + for (let k = len; k >= 1; k--) { + if (a.substring(l1 - k) === b.substring(0, k)) { + g[i][j] = k; + break; + } + } + } + } + const f = new Array(mask).fill(0).map(() => new Array(n).fill(0)); + const p = new Array(mask).fill(0).map(() => new Array(n).fill(0)); + for (let s = 0; s < mask; s++) { + for (let i = 0; i < n; i++) { + if (((s >> i) & 1) === 0) continue; + for (let j = 0; j < n; j++) { + if (((s >> j) & 1) === 1) continue; + if (f[s | (1 << j)][j] <= f[s][i] + g[i][j]) { + f[s | (1 << j)][j] = f[s][i] + g[i][j]; + p[s | (1 << j)][j] = i; + } + } + } + } + let max = f[mask - 1][0], idx = 0, last = -1, status = mask - 1; + for (let i = 1; i < n; i++) { + if (max < f[mask - 1][i]) { + max = f[mask - 1][i]; + idx = i; + } + } + let ans = ""; + while (status != 0) { + if (last === -1) ans = ws[idx]; + else ans = ws[idx].substring(0, ws[idx].length - g[idx][last]) + ans; + last = idx; + idx = p[status][idx]; + status ^= (1 << last); + } + return ans; +} +``` +* 时间复杂度:将字符串 $ws[i]$ 的最大长度记为 $C = 20$,预处理复杂度为 $O(n^2 \times C)$;状态数量为 $2^n$,`DP` 复杂度为 $O(2^n \times n^2)$。构造答案复杂度为 $O(n)$。整体复杂度为 $O(2^n\times n^2)$ +* 空间复杂度:$O(2^n \times n)$ + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.943` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 + diff --git "a/LeetCode/941-950/950. \346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/941-950/950. \346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214\357\274\210\344\270\255\347\255\211\357\274\211.md" new file mode 100644 index 00000000..1791f08b --- /dev/null +++ "b/LeetCode/941-950/950. \346\214\211\351\200\222\345\242\236\351\241\272\345\272\217\346\230\276\347\244\272\345\215\241\347\211\214\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -0,0 +1,149 @@ +### 题目描述 + +这是 LeetCode 上的 **[950. 按递增顺序显示卡牌](https://leetcode.cn/problems/reveal-cards-in-increasing-order/solution/gong-shui-san-xie-jian-dan-mo-ni-ti-by-a-nu48/)** ,难度为 **中等**。 + +Tag : 「模拟」、「队列」、「排序」、「构造」 + + + +牌组中的每张卡牌都对应有一个唯一的整数。你可以按你想要的顺序对这套卡片进行排序。 + +最初,这些卡牌在牌组里是正面朝下的(即,未显示状态)。 + +现在,重复执行以下步骤,直到显示所有卡牌为止: + +1. 从牌组顶部抽一张牌,显示它,然后将其从牌组中移出。 +2. 如果牌组中仍有牌,则将下一张处于牌组顶部的牌放在牌组的底部。 +3. 如果仍有未显示的牌,那么返回步骤 1。否则,停止行动。 + +返回能以递增顺序显示卡牌的牌组顺序。 + +答案中的第一张牌被认为处于牌堆顶部。 + + +示例: +``` +输入:[17,13,11,2,3,5,7] + +输出:[2,13,3,11,5,17,7] + +解释: +我们得到的牌组顺序为 [17,13,11,2,3,5,7](这个顺序不重要),然后将其重新排序。 +重新排序后,牌组以 [2,13,3,11,5,17,7] 开始,其中 2 位于牌组的顶部。 +我们显示 2,然后将 13 移到底部。牌组现在是 [3,11,5,17,7,13]。 +我们显示 3,并将 11 移到底部。牌组现在是 [5,17,7,13,11]。 +我们显示 5,然后将 17 移到底部。牌组现在是 [7,13,11,17]。 +我们显示 7,并将 13 移到底部。牌组现在是 [11,17,13]。 +我们显示 11,然后将 17 移到底部。牌组现在是 [13,17]。 +我们展示 13,然后将 17 移到底部。牌组现在是 [17]。 +我们显示 17。 +由于所有卡片都是按递增顺序排列显示的,所以答案是正确的。 +``` + +提示: +* $1 <= A.length <= 1000$ +* $1 <= A[i] <= 10^6$ +* 对于所有的 `i != j`,`A[i] != A[j]` + +--- + +### 模拟 + +根据题意,我们可以先使用双端队列对 `deck` 进行一次模拟,并用哈希表记下每个元素 $deck[i]$ 的显示顺序(利用 $deck[i]$ 元素各不相同,可直接用 $deck[i]$ 作为 `key`)。 + +随后考虑如何通过哈希表来构建答案数组 `ans`。 + +假设原数组中的 $deck[i]$ 为首次显示的卡牌,那么 $ans[i]$ 应该放置 `deck` 中最小的元素,同理若 $deck[j]$ 若最后显示的卡牌,则 $ans[j]$ 应放置 `deck` 中的最大元素。 + +为了方便找 `deck` 中第 $k$ 大元素,可对 `deck` 进行拷贝并排序。 + +Java 代码: +```Java +class Solution { + public int[] deckRevealedIncreasing(int[] deck) { + int n = deck.length, idx = 0; + Map map = new HashMap<>(); + Deque d = new ArrayDeque<>(); + for (int x : deck) d.addLast(x); + while (!d.isEmpty()) { + map.put(d.pollFirst(), idx++); + if (!d.isEmpty()) d.addLast(d.pollFirst()); + } + int[] ans = new int[n], temp = deck.clone(); + Arrays.sort(temp); + for (int i = 0; i < n; i++) ans[i] = temp[map.get(deck[i])]; + return ans; + } +} +``` +C++ 代码: +```C++ +class Solution { +public: + vector deckRevealedIncreasing(vector& deck) { + int n = deck.size(), idx = 0; + map map; + deque d; + for (int x : deck) d.push_back(x); + while (!d.empty()) { + map[d.front()] = idx++; + d.pop_front(); + if (!d.empty()) { + d.push_back(d.front()); + d.pop_front(); + } + } + vector ans(n); + vector temp = deck; + sort(temp.begin(), temp.end()); + for (int i = 0; i < n; i++) ans[i] = temp[map[deck[i]]]; + return ans; + } +}; +``` +Python3 代码: +```Python +class Solution: + def deckRevealedIncreasing(self, deck: List[int]) -> List[int]: + n, idx = len(deck), 0 + map = {} + d = deque(deck) + while d: + map[d.popleft()] = idx + idx += 1 + if d: + d.append(d.popleft()) + temp = sorted(deck) + return [temp[map[deck[i]]] for i in range(n)] +``` +TypeScript 代码: +```TypeScript +function deckRevealedIncreasing(deck: number[]): number[] { + let n = deck.length, idx = 0; + const map = {}; + const d = [...deck]; + while (d.length > 0) { + map[d.shift()!] = idx++; + if (d.length > 0) d.push(d.shift()!); + } + const ans = new Array(n); + const temp = [...deck].sort((a, b) => a - b); + for (let i = 0; i < n; i++) ans[i] = temp[map[deck[i]]]; + return ans; +}; +``` +* 时间复杂度:使用队列模拟一次操作的复杂度为 $O(n)$(每个元素只有一次出入队机会);对原数组进行复制并排序的复杂度 $O(n\log{n})$;构建答案复杂度为 $O(n)$。整体复杂度为 $O(n\log{n})$ +* 空间复杂度:$O(n)$ + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.950` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 + diff --git "a/LeetCode/981-990/985. \346\237\245\350\257\242\345\220\216\347\232\204\345\201\266\346\225\260\345\222\214\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/981-990/985. \346\237\245\350\257\242\345\220\216\347\232\204\345\201\266\346\225\260\345\222\214\357\274\210\344\270\255\347\255\211\357\274\211.md" new file mode 100644 index 00000000..0228ea07 --- /dev/null +++ "b/LeetCode/981-990/985. \346\237\245\350\257\242\345\220\216\347\232\204\345\201\266\346\225\260\345\222\214\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -0,0 +1,154 @@ +### 题目描述 + +这是 LeetCode 上的 **[985. 查询后的偶数和](https://leetcode.cn/problems/sum-of-even-numbers-after-queries/solution/gong-shui-san-xie-jian-dan-mo-ni-ti-by-a-lwfq/)** ,难度为 **中等**。 + +Tag : 「模拟」 + + + +给出一个整数数组 `A` 和一个查询数组 `queries`。 + +对于第 `i` 次查询,有 `val = queries[i][0]`, `index = queries[i][1]`,我们会把 `val` 加到 `A[index]` 上。然后,第 `i` 次查询的答案是 `A` 中偶数值的和。 + +(此处给定的 `index = queries[i][1]` 是从 `0` 开始的索引,每次查询都会永久修改数组 `A`。) + +返回所有查询的答案。你的答案应当以数组 `answer` 给出,`answer[i]` 为第 `i` 次查询的答案。 + +示例: +``` +输入:A = [1,2,3,4], queries = [[1,0],[-3,1],[-4,0],[2,3]] + +输出:[8,6,2,4] + +解释: +开始时,数组为 [1,2,3,4]。 +将 1 加到 A[0] 上之后,数组为 [2,2,3,4],偶数值之和为 2 + 2 + 4 = 8。 +将 -3 加到 A[1] 上之后,数组为 [2,-1,3,4],偶数值之和为 2 + 4 = 6。 +将 -4 加到 A[0] 上之后,数组为 [-2,-1,3,4],偶数值之和为 -2 + 4 = 2。 +将 2 加到 A[3] 上之后,数组为 [-2,-1,3,6],偶数值之和为 -2 + 6 = 4。 +``` + +提示: +* $1 <= A.length <= 10000$ +* $-10000 <= A[i] <= 10000$ +* $1 <= queries.length <= 10000$ +* $-10000 <= queries[i][0] <= 10000$ +* $0 <= queries[i][1] < A.length$ + +--- + +### 模拟 + +为了方便,将 `queries` 记为 `qs`。 + +由于每次修改都是对 `A` 的永久修改,因此我们使用一个变量 `t` 来记录当前所有偶数和即可。 + +具体的,我们先统计原数组所有偶数和为 `t`,从前往后处理每个 $qs[i]$,若修改前的原值 $nums[qs[i][1]]$ 为偶数,我们需要将其从 `t` 中减去,再进行实际修改 `nums[qs[i][1]] += qs[i][0]`,若修改后值为偶数,则将其累加到 `t` 上。 + +Java 代码: +```Java +class Solution { + public int[] sumEvenAfterQueries(int[] nums, int[][] qs) { + int m = qs.length, t = 0; + int[] ans = new int[m]; + for (int x : nums) t += x % 2 == 0 ? x : 0; + for (int i = 0; i < m; i++) { + int val = qs[i][0], idx = qs[i][1]; + if (nums[idx] % 2 == 0) t -= nums[idx]; + nums[idx] += val; + if (nums[idx] % 2 == 0) t += nums[idx]; + ans[i] = t; + } + return ans; + } +} +``` +C++ 代码: +```C++ +class Solution { +public: + vector sumEvenAfterQueries(vector& nums, vector>& qs) { + int m = qs.size(), t = 0; + std::vector ans(m); + for (int x : nums) t += x % 2 == 0 ? x : 0; + for (int i = 0; i < m; i++) { + int val = qs[i][0], idx = qs[i][1]; + if (nums[idx] % 2 == 0) t -= nums[idx]; + nums[idx] += val; + if (nums[idx] % 2 == 0) t += nums[idx]; + ans[i] = t; + } + return ans; + } +}; +``` +Python3 代码: +```Python3 +class Solution: + def sumEvenAfterQueries(self, nums: List[int], qs: List[List[int]]) -> List[int]: + m, t = 0, sum(x for x in nums if x % 2 == 0) + ans = [] + for val, idx in qs: + if nums[idx] % 2 == 0: + t -= nums[idx] + nums[idx] += val + if nums[idx] % 2 == 0: + t += nums[idx] + ans.append(t) + return ans +``` +Go 代码: +```Go +func sumEvenAfterQueries(nums []int, qs [][]int) []int { + m, t := len(qs), 0 + ans := make([]int, m) + for _, x := range nums { + if x % 2 == 0 { + t += x + } + } + for i := 0; i < m; i++ { + val, idx := qs[i][0], qs[i][1] + if nums[idx] % 2 == 0 { + t -= nums[idx] + } + nums[idx] += val + if nums[idx] % 2 == 0 { + t += nums[idx] + } + ans[i] = t + } + return ans +} +``` +TypeScript 代码: +```TypeScript +function sumEvenAfterQueries(nums: number[], qs: number[][]): number[] { + let m = qs.length, t = 0 + for (const x of nums) t += x % 2 == 0 ? x : 0 + const ans = new Array(m) + for (let i = 0; i < m; i++) { + const val = qs[i][0], idx = qs[i][1] + if (nums[idx] % 2 == 0) t -= nums[idx] + nums[idx] += val + if (nums[idx] % 2 == 0) t += nums[idx] + ans[i] = t; + } + return ans +}; +``` +* 时间复杂度:$O(n)$ +* 空间复杂度:$O(1)$ + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.985` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 +