diff --git "a/Index/\344\272\214\345\217\211\346\240\221.md" "b/Index/\344\272\214\345\217\211\346\240\221.md" index 01671e34..1a8b6f2e 100644 --- "a/Index/\344\272\214\345\217\211\346\240\221.md" +++ "b/Index/\344\272\214\345\217\211\346\240\221.md" @@ -34,6 +34,7 @@ | [987. 二叉树的垂序遍历](https://leetcode-cn.com/problems/vertical-order-traversal-of-a-binary-tree/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/vertical-order-traversal-of-a-binary-tree/solution/gong-shui-san-xie-yi-ti-shuang-jie-dfs-h-wfm3/) | 困难 | 🤩🤩🤩🤩🤩 | | [993. 二叉树的堂兄弟节点](https://leetcode-cn.com/problems/cousins-in-binary-tree/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/cousins-in-binary-tree/solution/gong-shui-san-xie-shu-de-sou-suo-dfs-bfs-b200/) | 简单 | 🤩🤩 | | [1022. 从根到叶的二进制数之和](https://leetcode.cn/problems/sum-of-root-to-leaf-binary-numbers/) | [LeetCode 题解链接](https://leetcode.cn/problems/sum-of-root-to-leaf-binary-numbers/solution/by-ac_oier-1905/) | 简单 | 🤩🤩🤩🤩 | +| [1038. 从二叉搜索树到更大和树](https://leetcode.cn/problems/binary-search-tree-to-greater-sum-tree/) | [LeetCode 题解链接](https://leetcode.cn/problems/binary-search-tree-to-greater-sum-tree/solutions/2552959/gong-shui-san-xie-bst-de-zhong-xu-bian-l-vtu1/) | 中等 | 🤩🤩🤩🤩 | | [1104. 二叉树寻路](https://leetcode-cn.com/problems/path-in-zigzag-labelled-binary-tree/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/path-in-zigzag-labelled-binary-tree/solution/gong-shui-san-xie-yi-ti-shuang-jie-mo-ni-rw2d/) | 中等 | 🤩🤩🤩 | | [1305. 两棵二叉搜索树中的所有元素](https://leetcode-cn.com/problems/all-elements-in-two-binary-search-trees/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/all-elements-in-two-binary-search-trees/solution/by-ac_oier-c8fv/) | 中等 | 🤩🤩🤩🤩 | | [剑指 Offer 04. 二维数组中的查找](https://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/) | [LeetCode 题解链接](https://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/solution/by-ac_oier-7jo0/) | 中等 | 🤩🤩🤩🤩🤩 | @@ -43,4 +44,3 @@ | [剑指 Offer 34. 二叉树中和为某一值的路径](https://leetcode.cn/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof/) | [LeetCode 题解链接](https://leetcode.cn/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof/solution/by-ac_oier-3ehr/) | 中等 | 🤩🤩🤩🤩🤩 | | [剑指 Offer 37. 序列化二叉树](https://leetcode-cn.com/problems/xu-lie-hua-er-cha-shu-lcof/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/xu-lie-hua-er-cha-shu-lcof/solution/gong-shui-san-xie-er-cha-shu-de-xu-lie-h-n89a/) | 困难 | 🤩🤩🤩🤩🤩 | | [面试题 04.06. 后继者](https://leetcode.cn/problems/successor-lcci/) | [LeetCode 题解链接](https://leetcode.cn/problems/successor-lcci/solution/by-ac_oier-xib5/) | 中等 | 🤩🤩🤩🤩🤩 | - diff --git "a/Index/\345\211\215\347\274\200\345\222\214.md" "b/Index/\345\211\215\347\274\200\345\222\214.md" index 7111aedd..9badffe1 100644 --- "a/Index/\345\211\215\347\274\200\345\222\214.md" +++ "b/Index/\345\211\215\347\274\200\345\222\214.md" @@ -27,6 +27,7 @@ | [930. 和相同的二元子数组](https://leetcode-cn.com/problems/binary-subarrays-with-sum/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/binary-subarrays-with-sum/solution/gong-shui-san-xie-yi-ti-shuang-jie-qian-hfoc0/) | 中等 | 🤩🤩🤩 | | [1004. 最大连续1的个数 III](https://leetcode-cn.com/problems/max-consecutive-ones-iii/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/san-chong-jie-fa-cong-dong-tai-gui-hua-d-gxks/) | 中等 | 🤩🤩🤩 | | [1074. 元素和为目标值的子矩阵数量](https://leetcode-cn.com/problems/number-of-submatrices-that-sum-to-target/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/number-of-submatrices-that-sum-to-target/solution/gong-shui-san-xie-you-hua-mei-ju-de-ji-b-uttw/) | 困难 | 🤩🤩🤩 | +| [1094. 拼车](https://leetcode.cn/problems/car-pooling/) | [LeetCode 题解链接](https://leetcode.cn/problems/car-pooling/solutions/2550276/gong-shui-san-xie-tu-jie-chai-fen-ru-men-opii/) | 中等 | 🤩🤩🤩🤩🤩 | | [1154. 一年中的第几天](https://leetcode-cn.com/problems/day-of-the-year/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/day-of-the-year/solution/gong-shui-san-xie-jian-dan-qian-zhui-he-lwo2g/) | 简单 | 🤩🤩🤩🤩 | | [1208. 尽可能使字符串相等](https://leetcode-cn.com/problems/get-equal-substrings-within-budget/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/get-equal-substrings-within-budget/solution/ni-bu-ke-neng-kan-bu-dong-de-qian-zhui-h-u4l1/) | 中等 | 🤩🤩🤩 | | [1310. 子数组异或查询](https://leetcode-cn.com/problems/xor-queries-of-a-subarray/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/xor-queries-of-a-subarray/solution/gong-shui-san-xie-yi-ti-shuang-jie-shu-z-rcgu/) | 中等 | 🤩🤩🤩🤩 | 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 3dcc2f13..0dfd7f70 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" @@ -95,6 +95,7 @@ | [2034. 股票价格波动](https://leetcode-cn.com/problems/stock-price-fluctuation/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/stock-price-fluctuation/solution/gong-shui-san-xie-shu-ju-jie-gou-mo-ni-t-u6f4/) | 中等 | 🤩🤩🤩🤩 | | [2336. 无限集中的最小数字](https://leetcode.cn/problems/smallest-number-in-infinite-set/) | [LeetCode 题解链接](https://leetcode.cn/problems/smallest-number-in-infinite-set/solutions/2546157/gong-shui-san-xie-rong-yi-you-gao-xiao-d-431o/) | 中等 | 🤩🤩🤩🤩 | | [2342. 数位和相等数对的最大和](https://leetcode.cn/problems/max-sum-of-a-pair-with-equal-sum-of-digits/) | [LeetCode 题解链接](https://leetcode.cn/problems/max-sum-of-a-pair-with-equal-sum-of-digits/solutions/2531511/gong-shui-san-xie-yong-bian-li-guo-cheng-kt3f/) | 中等 | 🤩🤩🤩🤩 | +| [2661. 找出叠涂元素](https://leetcode.cn/problems/first-completely-painted-row-or-column/) | [LeetCode 题解链接](https://leetcode.cn/problems/first-completely-painted-row-or-column/solutions/2549034/gong-shui-san-xie-chang-gui-ha-xi-biao-y-jkxa/) | 中等 | 🤩🤩🤩🤩 | | [面试题 10.02. 变位词组](https://leetcode-cn.com/problems/group-anagrams-lcci/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/group-anagrams-lcci/solution/gong-shui-san-xie-tong-ji-bian-wei-ci-de-0iqe/) | 中等 | 🤩🤩🤩🤩 | | [面试题 17.10. 主要元素](https://leetcode-cn.com/problems/find-majority-element-lcci/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/find-majority-element-lcci/solution/gong-shui-san-xie-yi-ti-shuang-jie-ha-xi-zkht/) | 简单 | 🤩🤩🤩🤩 | | [剑指 Offer 35. 复杂链表的复制](https://leetcode.cn/problems/fu-za-lian-biao-de-fu-zhi-lcof/) | [LeetCode 题解链接](https://leetcode.cn/problems/fu-za-lian-biao-de-fu-zhi-lcof/solution/by-ac_oier-6atv/) | 中等 | 🤩🤩🤩 | diff --git "a/Index/\345\233\276\350\256\272 DFS.md" "b/Index/\345\233\276\350\256\272 DFS.md" index c914ff93..abbedd14 100644 --- "a/Index/\345\233\276\350\256\272 DFS.md" +++ "b/Index/\345\233\276\350\256\272 DFS.md" @@ -16,5 +16,6 @@ | [2003. 每棵子树内缺失的最小基因值](https://leetcode.cn/problems/smallest-missing-genetic-value-in-each-subtree/) | [LeetCode 题解链接](https://leetcode.cn/problems/smallest-missing-genetic-value-in-each-subtree/solutions/2505877/gong-shui-san-xie-tu-jie-san-da-jie-lun-mxjrn/) | 困难 | 🤩🤩🤩🤩🤩 | | [2049. 统计最高分的节点数目](https://leetcode-cn.com/problems/count-nodes-with-the-highest-score/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/count-nodes-with-the-highest-score/solution/gong-shui-san-xie-jian-tu-dfs-by-ac_oier-ujfo/) | 中等 | 🤩🤩🤩🤩 | | [2246. 相邻字符不同的最长路径](https://leetcode.cn/problems/longest-path-with-different-adjacent-characters/) | [LeetCode 题解链接](https://leetcode.cn/problems/longest-path-with-different-adjacent-characters/solutions/2453857/gong-shui-san-xie-shu-xing-dp-ding-gen-d-eh5i/) | 困难 | 🤩🤩🤩🤩🤩 | +| [2477. 到达首都的最少油耗](https://leetcode.cn/problems/minimum-fuel-cost-to-report-to-the-capital/) | [LeetCode 题解链接](https://leetcode.cn/problems/minimum-fuel-cost-to-report-to-the-capital/solutions/2554316/gong-shui-san-xie-zhu-bu-jiang-jie-zui-d-25qs/) | 中等 | 🤩🤩🤩🤩 | | [LCP 07. 传递信息](https://leetcode-cn.com/problems/chuan-di-xin-xi/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/chuan-di-xin-xi/solution/gong-shui-san-xie-tu-lun-sou-suo-yu-dong-cyxo/) | 简单 | 🤩🤩🤩🤩 | diff --git "a/Index/\345\267\256\345\210\206.md" "b/Index/\345\267\256\345\210\206.md" index fe760a56..b9b9819b 100644 --- "a/Index/\345\267\256\345\210\206.md" +++ "b/Index/\345\267\256\345\210\206.md" @@ -2,6 +2,7 @@ | ------------------------------------------------------------ | ------------------------------------------------------------ | ---- | -------- | | [798. 得分最高的最小轮调](https://leetcode-cn.com/problems/smallest-rotation-with-highest-score/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/smallest-rotation-with-highest-score/solution/gong-shui-san-xie-shang-xia-jie-fen-xi-c-p6kh/) | 困难 | 🤩🤩🤩🤩 | | [995. K 连续位的最小翻转次数](https://leetcode-cn.com/problems/minimum-number-of-k-consecutive-bit-flips/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/minimum-number-of-k-consecutive-bit-flips/solution/po-su-tan-xin-jie-fa-yu-tan-xin-chai-fen-4lyy/) | 困难 | 🤩🤩🤩 | +| [1094. 拼车](https://leetcode.cn/problems/car-pooling/) | [LeetCode 题解链接](https://leetcode.cn/problems/car-pooling/solutions/2550276/gong-shui-san-xie-tu-jie-chai-fen-ru-men-opii/) | 中等 | 🤩🤩🤩🤩🤩 | | [1109. 航班预订统计](https://leetcode-cn.com/problems/corporate-flight-bookings/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/corporate-flight-bookings/solution/gong-shui-san-xie-yi-ti-shuang-jie-chai-fm1ef/) | 中等 | 🤩🤩🤩🤩🤩 | | [1450. 在既定时间做作业的学生人数](https://leetcode.cn/problems/number-of-students-doing-homework-at-a-given-time/) | [LeetCode 题解链接](https://leetcode.cn/problems/number-of-students-doing-homework-at-a-given-time/solution/by-ac_oier-4ftz/) | 简单 | 🤩🤩🤩🤩🤩 | diff --git "a/Index/\346\250\241\346\213\237.md" "b/Index/\346\250\241\346\213\237.md" index 189bde2d..bdd7bb63 100644 --- "a/Index/\346\250\241\346\213\237.md" +++ "b/Index/\346\250\241\346\213\237.md" @@ -253,6 +253,7 @@ | [2520. 统计能整除数字的位数](https://leetcode.cn/problems/count-the-digits-that-divide-a-number/) | [LeetCode 题解链接](https://leetcode.cn/problems/count-the-digits-that-divide-a-number/solutions/2498966/gong-shui-san-xie-jian-dan-mo-ni-ti-shi-0ad2c/) | 简单 | 🤩🤩🤩🤩🤩 | | [2586. 统计范围内的元音字符串数](https://leetcode.cn/problems/count-the-number-of-vowel-strings-in-range/) | [LeetCode 题解链接](https://leetcode.cn/problems/count-the-number-of-vowel-strings-in-range/solutions/2515898/gong-shui-san-xie-jian-dan-zi-fu-chuan-m-di1t/) | 简单 | 🤩🤩🤩 | | [2609. 最长平衡子字符串](https://leetcode.cn/problems/find-the-longest-balanced-substring-of-a-binary-string/) | [LeetCode 题解链接](https://leetcode.cn/problems/find-the-longest-balanced-substring-of-a-binary-string/solutions/2517437/gong-shui-san-xie-on-shi-jian-o1-kong-ji-i8e7/) | 简单 | 🤩🤩🤩 | +| [2661. 找出叠涂元素](https://leetcode.cn/problems/first-completely-painted-row-or-column/) | [LeetCode 题解链接](https://leetcode.cn/problems/first-completely-painted-row-or-column/solutions/2549034/gong-shui-san-xie-chang-gui-ha-xi-biao-y-jkxa/) | 中等 | 🤩🤩🤩🤩 | | [面试题 01.02. 判定是否互为字符重排](https://leetcode.cn/problems/check-permutation-lcci/) | [LeetCode 题解链接](https://leetcode.cn/problems/check-permutation-lcci/solution/by-ac_oier-qj3j/) | 简单 | 🤩🤩🤩 | | [面试题 01.05. 一次编辑](https://leetcode.cn/problems/one-away-lcci/) | [LeetCode 题解链接](https://leetcode.cn/problems/one-away-lcci/solution/by-ac_oier-7ml0/) | 中等 | 🤩🤩🤩🤩 | | [面试题 01.08. 零矩阵](https://leetcode.cn/problems/zero-matrix-lcci/) | [LeetCode 题解链接](https://leetcode.cn/problems/zero-matrix-lcci/solution/by-ac_oier-0lo0/) | 中等 | 🤩🤩🤩🤩 | diff --git "a/Index/\346\273\221\345\212\250\347\252\227\345\217\243.md" "b/Index/\346\273\221\345\212\250\347\252\227\345\217\243.md" index a76cba70..79d616aa 100644 --- "a/Index/\346\273\221\345\212\250\347\252\227\345\217\243.md" +++ "b/Index/\346\273\221\345\212\250\347\252\227\345\217\243.md" @@ -18,7 +18,7 @@ | [1004. 最大连续1的个数 III](https://leetcode-cn.com/problems/max-consecutive-ones-iii/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/san-chong-jie-fa-cong-dong-tai-gui-hua-d-gxks/) | 中等 | 🤩🤩🤩 | | [1052. 爱生气的书店老板](https://leetcode-cn.com/problems/grumpy-bookstore-owner/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/grumpy-bookstore-owner/solution/hua-dong-chuang-kou-luo-ti-by-ac_oier-nunu/) | 中等 | 🤩🤩🤩 | | [1208. 尽可能使字符串相等](https://leetcode-cn.com/problems/get-equal-substrings-within-budget/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/get-equal-substrings-within-budget/solution/ni-bu-ke-neng-kan-bu-dong-de-qian-zhui-h-u4l1/) | 中等 | 🤩🤩🤩 | -| [1423. 可获得的最大点数](https://leetcode-cn.com/problems/maximum-points-you-can-obtain-from-cards/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/maximum-points-you-can-obtain-from-cards/solution/jian-dan-de-hua-dong-chuang-kou-he-kuai-1go5h/) | 中等 | 🤩🤩🤩🤩 | +| [1423. 可获得的最大点数](https://leetcode-cn.com/problems/maximum-points-you-can-obtain-from-cards/) | [LeetCode 题解链接](https://leetcode.cn/problems/maximum-points-you-can-obtain-from-cards/solutions/2551466/gong-shui-san-xie-zhuan-huan-wei-gu-ding-pbvd/) | 中等 | 🤩🤩🤩🤩 | | [1438. 绝对差不超过限制的最长连续子数组](https://leetcode-cn.com/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit/solution/xiang-jie-er-fen-hua-dong-chuang-kou-dan-41g1/) | 中等 | 🤩🤩🤩 | | [1610. 可见点的最大数目](https://leetcode-cn.com/problems/maximum-number-of-visible-points/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/maximum-number-of-visible-points/solution/gong-shui-san-xie-qiu-ji-jiao-ji-he-ti-b-0bid/) | 困难 | 🤩🤩🤩🤩 | | [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/) | 中等 | 🤩🤩🤩 | diff --git "a/LeetCode/1031-1040/1038. \344\273\216\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\345\210\260\346\233\264\345\244\247\345\222\214\346\240\221\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1031-1040/1038. \344\273\216\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\345\210\260\346\233\264\345\244\247\345\222\214\346\240\221\357\274\210\344\270\255\347\255\211\357\274\211.md" new file mode 100644 index 00000000..e71b4a6e --- /dev/null +++ "b/LeetCode/1031-1040/1038. \344\273\216\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\345\210\260\346\233\264\345\244\247\345\222\214\346\240\221\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -0,0 +1,128 @@ +### 题目描述 + +这是 LeetCode 上的 **[1038. 从二叉搜索树到更大和树](https://leetcode.cn/problems/binary-search-tree-to-greater-sum-tree/solutions/2552959/gong-shui-san-xie-bst-de-zhong-xu-bian-l-vtu1/)** ,难度为 **中等**。 + +Tag : 「BST」、「中序遍历」 + + + +给定一个二叉搜索树 `root` (BST),请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。 + +提醒一下, 二叉搜索树满足下列约束条件: + +* 节点的左子树仅包含键小于节点键的节点。 +* 节点的右子树仅包含键大于节点键的节点。 +* 左右子树也必须是二叉搜索树。 + +示例 1: +![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2019/05/03/tree.png) +``` +输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8] + +输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8] +``` +示例 2: +``` +输入:root = [0,null,1] + +输出:[1,null,1] +``` + +提示: +* 树中的节点数在 $[1, 100]$ 范围内。 +* $0 <= Node.val <= 100$ +* 树中的所有值均不重复 。 + +--- + +### 中序遍历 + +利用 **`BST` 的中序遍历是有序** 的特性,我们可以通过两次遍历 `BST` 来求解问题。 + +首先,通过一次遍历,计算出整棵树的节点总和 `tot`,然后在中序遍历过程中,不断对 `tot` 进行更新,将其作为当前未遍历到的节点的总和,用于给当前节点赋值。 + +假设当前遍历到的节点为 `x`(起始节点值为 `t`),那么将节点更新为当前节点 `tot` 后,更新 `tot = tot - t`。 + +这是常规的中序遍历做法,更进一步,如果将其中序遍历的顺序进行翻转(从「左中右」调整为「右中左」),则可实现一次遍历。 + + +Java 代码: +```Java +class Solution { + int tot = 0; + public TreeNode bstToGst(TreeNode root) { + dfs(root); + return root; + } + void dfs(TreeNode root) { + if (root == null) return ; + dfs(root.right); + tot += root.val; + root.val = tot; + dfs(root.left); + } +} +``` +C++ 代码: +```C++ +class Solution { +public: + int tot = 0; + TreeNode* bstToGst(TreeNode* root) { + dfs(root); + return root; + } + void dfs(TreeNode* root) { + if (root == nullptr) return; + dfs(root->right); + tot += root->val; + root->val = tot; + dfs(root->left); + } +}; +``` +Python 代码: +```Python +class Solution: + def bstToGst(self, root: TreeNode) -> TreeNode: + tot = 0 + def dfs(root): + nonlocal tot + if not root: return + dfs(root.right) + tot += root.val + root.val = tot + dfs(root.left) + dfs(root) + return root +``` +TypeScript 代码: +```TypeScript +function bstToGst(root: TreeNode | null): TreeNode | null { + let tot = 0; + const dfs = function(root: TreeNode | null): void { + if (!root) return ; + dfs(root.right); + tot += root.val; + root.val = tot; + dfs(root.left); + } + dfs(root); + return root; +}; +``` +* 时间复杂度:$O(n)$ +* 空间复杂度:$O(n)$ + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.1038` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 + diff --git "a/LeetCode/1091-1100/1094. \346\213\274\350\275\246\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1091-1100/1094. \346\213\274\350\275\246\357\274\210\344\270\255\347\255\211\357\274\211.md" new file mode 100644 index 00000000..8dff26bb --- /dev/null +++ "b/LeetCode/1091-1100/1094. \346\213\274\350\275\246\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -0,0 +1,158 @@ +### 题目描述 + +这是 LeetCode 上的 **[1094. 拼车](https://leetcode.cn/problems/car-pooling/solutions/2550276/gong-shui-san-xie-tu-jie-chai-fen-ru-men-opii/)** ,难度为 **中等**。 + +Tag : 「差分」、「前缀和」 + + + +车上最初有 `capacity` 个空座位,车只能向一个方向行驶(不允许掉头或改变方向)。 + +给定整数 `capacity` 和一个数组 `trips`, $trip[i] = [numPassengers_{i}, from_{i}, to_{i}]$ 表示第 `i` 次旅行有 $numPassengers_{i}$ 乘客,接他们和放他们的位置分别是 $from_{i}$ 和 $to_{i}$ 。 + +这些位置是从汽车的初始位置向东的公里数。 + +当且仅当你可以在所有给定的行程中接送所有乘客时,返回 `true`,否则请返回 `false`。 + +示例 1: +``` +输入:trips = [[2,1,5],[3,3,7]], capacity = 4 + +输出:false +``` +示例 2: +``` +输入:trips = [[2,1,5],[3,3,7]], capacity = 5 + +输出:true +``` + +提示: +* $1 <= trips.length <= 1000$ +* $trips[i].length = 3$ +* $1 <= numPassengers_{i} <= 100$ +* $0 <= from_{i} < to_{i} <= 1000$ +* $1 <= capacity <= 10^5$ + +--- + +### 差分 + +从朴素的想法开始:创建一个数组 `cnt`,用于存储从某个站点出发时,车上的乘客数量。 + +例如 $cnt[x] = c$ 含义为在站点 $x$ 出发时(在该站点的下车和上车均完成),车上乘客数为 $c$ 个。 + +对于每个 $trips[i] = (c, a, b)$,我们需要对 $[a, b)$ 范围内的 $cnt[j]$ 进行加 $c$ 操作。 + +处理完 `trips` 后,检查所有站点的乘客人数,根据是否满足 `capacity` 限制返回答案。 + +因此,这是一个关于「区间修改,单点查询」的经典问题,可使用「差分」求解。 + +所谓“差分”,是指 **原数组中每个元素与前一元素之差所形成的数组**,与之相对应的是“前缀和”。 + +我们知道,对原数组进行诸位累加(前缀计算操作),所得到的数组为前缀和数组。差分数组,则是对其执行前缀计算后,能够得到原数组的那个数组 🤣 。 + +关于「差分数组 - 原数组 - 前缀和数组」三者关系如图所示: + +![](https://pic.leetcode.cn/1701478324-ArYSEo-image.png) + +前缀和数组的主要作用,是利用「容斥原理」快速求解某段之和。例如要查询原数组 `nums` 中下标范围 $[l, r]$ 的和,可通过 $sum[r] - sum[l - 1]$ 快速求解。 + +差分数组的主要作用,是帮助快速修改某段区间。 + +由于差分数组执行「前缀计算」后得到的是原数组,因此在差分数组上修改某个值,会对原数组某段后缀产生相同的影响。 + +![](https://pic.leetcode.cn/1701478248-GRSIwG-image.png) + +因此,**当我们想要对原数组的 $[l, r]$ 进行整体修改时,只需要对差分数组的 $l$ 和 $r + 1$ 位置执行相应操作即可**。 + +举个 🌰,假设想对原数组 `nums` 的 $[l, r]$ 进行整体“加一”操作,那么可转换为对差分数组 `c[l]` 的加一操作(等价对原数组的 $[l, n - 1]$ 进行加一),以及对差分数组 `c[r + 1]` 的减一操作(等价于对原数组的 $[r + 1, n - 1]$ 进行减一,最终只有 $[l, r]$ 有加一效果)。 + +至此,我们完成了对「差分」的基本学习:**将原数组的区间修改等价为差分数组的特定位置修改**。 + +回到本题,起始先用 `nums` 来作为差分数组,对于 $trips[i] = (c, a, b)$,有 $c$ 个乘客在 $a$ 点上车,在 $b$ 点下车,因此对 $[a, b)$ 进行整体加 $c$ 操作,对应差分数组操作 `nums[a] += c; nums[b] -= c`。 + +处理完 `trips` 后,对差分数组 `nums` 进行前缀计算(可直接复用 `nums`,进行原地计算),便可得到各个站点的乘客数量,与 `capacity` 比较得出答案。 + +一些细节:为了方便,人为规定站点编号从 $1$ 开始。 + +Java 代码: + +```Java +class Solution { + public boolean carPooling(int[][] trips, int capacity) { + int[] nums = new int[1010]; + for (int[] t : trips) { + int c = t[0], a = t[1], b = t[2]; + nums[a + 1] += c; nums[b + 1] -= c; + } + for (int i = 1; i <= 1000; i++) { + nums[i] += nums[i - 1]; + if (nums[i] > capacity) return false; + } + return true; + } +} +``` +C++ 代码: +```C++ +class Solution { +public: + bool carPooling(vector>& trips, int capacity) { + vector nums(1010, 0); + for (const auto& t : trips) { + int c = t[0], a = t[1], b = t[2]; + nums[a + 1] += c; nums[b + 1] -= c; + } + for (int i = 1; i <= 1000; i++) { + nums[i] += nums[i - 1]; + if (nums[i] > capacity) return false; + } + return true; + } +}; +``` +Python 代码: +```Python +class Solution: + def carPooling(self, trips: List[List[int]], capacity: int) -> bool: + nums = [0] * 1010 + for t in trips: + c, a, b = t[0], t[1], t[2] + nums[a + 1] += c + nums[b + 1] -= c + for i in range(1, 1001): + nums[i] += nums[i - 1] + if nums[i] > capacity: return False + return True +``` +TypeScript 代码: +```TypeScript +function carPooling(trips: number[][], capacity: number): boolean { + const nums = new Array(1010).fill(0); + for (const t of trips) { + const c = t[0], a = t[1], b = t[2]; + nums[a + 1] += c; nums[b + 1] -= c; + } + for (let i = 1; i <= 1000; i++) { + nums[i] += nums[i - 1]; + if (nums[i] > capacity) return false; + } + return true; +}; +``` +* 时间复杂度:$O(n + m)$,其中 $n$ 为数组 `trips` 大小;$m = 1000$ 为位置值域大小 +* 空间复杂度:$O(m)$ + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.1094` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 + diff --git "a/LeetCode/1421-1430/1423. \345\217\257\350\216\267\345\276\227\347\232\204\346\234\200\345\244\247\347\202\271\346\225\260\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1421-1430/1423. \345\217\257\350\216\267\345\276\227\347\232\204\346\234\200\345\244\247\347\202\271\346\225\260\357\274\210\344\270\255\347\255\211\357\274\211.md" index 7a286de5..18a7e91e 100644 --- "a/LeetCode/1421-1430/1423. \345\217\257\350\216\267\345\276\227\347\232\204\346\234\200\345\244\247\347\202\271\346\225\260\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/1421-1430/1423. \345\217\257\350\216\267\345\276\227\347\232\204\346\234\200\345\244\247\347\202\271\346\225\260\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -1,21 +1,18 @@ ### 题目描述 -这是 LeetCode 上的 **[1423. 可获得的最大点数](https://leetcode-cn.com/problems/maximum-points-you-can-obtain-from-cards/solution/jian-dan-de-hua-dong-chuang-kou-he-kuai-1go5h/)** ,难度为 **中等**。 +这是 LeetCode 上的 **[1423. 可获得的最大点数](https://leetcode.cn/problems/maximum-points-you-can-obtain-from-cards/solutions/2551466/gong-shui-san-xie-zhuan-huan-wei-gu-ding-pbvd/)** ,难度为 **中等**。 Tag : 「滑动窗口」 +几张卡牌排成一行,每张卡牌都有一个对应的点数,点数由整数数组 `cardPoints` 给出。 -几张卡牌 排成一行,每张卡牌都有一个对应的点数。点数由整数数组 cardPoints 给出。 - -每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 k 张卡牌。 +每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 `k` 张卡牌。 你的点数就是你拿到手中的所有卡牌的点数之和。 -给你一个整数数组 cardPoints 和整数 k,请你返回可以获得的最大点数。 - - +给你一个整数数组 `cardPoints` 和整数 `k`,请你返回可以获得的最大点数。 示例 1: ``` @@ -57,48 +54,87 @@ Tag : 「滑动窗口」 ``` 提示: -* 1 <= cardPoints.length <= $10^5$ -* 1 <= cardPoints[i] <= $10^4$ -* 1 <= k <= cardPoints.length +* $1 <= cardPoints.length <= 10^5$ +* $1 <= cardPoints[i] <= 10^4$ +* $1 <= k <= cardPoints.length$ --- ### 滑动窗口 -简单的推导: - -从两边选择卡片,选择 `k` 张,卡片的总数量为 `n` 张,即有 `n - k` 张不被选择。 +从两边选卡片,选 `k` 张,卡片总数量为 `n` 张,即有 `n - k` 张不被选择。 -所有卡边的总和 `sum` 固定,要使选择的 `k` 张的总和最大,反过来就是要让不被选择的 `n - k` 张的总和最小。 +所有卡片总和 `sum` 固定,要使选择的 `k` 张的总和最大,反过来就是要让不被选择的 `n - k` 张总和最小。 -可以使用滑动窗口来计算 `n - k` 张卡片的最小总和 `min`,最终答案为 `sum - min`。 +原问题等价为:**从 `cardPoints` 中找长度为 `n - k` 的连续段,使其总和最小。** -以下代码,可以作为滑动窗口模板使用: +具体的,用变量 `sum` 代指 `cardPoints` 总和,`cur` 代表长度固定为 `n - k` 的当前窗口总和,`minv` 代表所有长度为 `n - k` 的窗口中总和最小的值。 -*PS. 你会发现以下代码和 [643. 子数组最大平均数 I](https://leetcode-cn.com/problems/maximum-average-subarray-i/solution/hua-dong-chuang-kou-luo-ti-han-mo-ban-by-buo3/) 代码很相似,因为是一套模板,所以说这道其实是道简单题,只是多了一个小学奥数难度的等式推导过程 ~* +起始先将滑动窗口压满,取得第一个滑动窗口的目标值 `cur`(同时更新为 `minv`),随后往后继续处理 `cardPoints`,每往前滑动一位,需要删除一个和添加一个元素,并不断更新 `minv`,最终 `sum - minv` 即是答案。 -1. 初始化将滑动窗口压满,取得第一个滑动窗口的目标值 - -2. 继续滑动窗口,每往前滑动一次,需要删除一个和添加一个元素 - -代码: +Java 代码: ```Java class Solution { - public int maxScore(int[] nums, int k) { - int n = nums.length, len = n - k; + public int maxScore(int[] cardPoints, int k) { + int n = cardPoints.length, len = n - k; int sum = 0, cur = 0; - for (int i = 0; i < n; i++) sum += nums[i]; - for (int i = 0; i < len; i++) cur += nums[i]; - int min = cur; + for (int i = 0; i < n; i++) sum += cardPoints[i]; + for (int i = 0; i < len; i++) cur += cardPoints[i]; + int minv = cur; for (int i = len; i < n; i++) { - cur = cur + nums[i] - nums[i - len]; - min = Math.min(min, cur); + cur = cur + cardPoints[i] - cardPoints[i - len]; + minv = Math.min(minv, cur); } - return sum - min; + return sum - minv; } } ``` -* 时间复杂度:每个元素最多滑入和滑出窗口一次。复杂度为 $O(n)$ +C++ 代码: +```C++ +class Solution { +public: + int maxScore(vector& cardPoints, int k) { + int n = cardPoints.size(), len = n - k; + int sum = 0, cur = 0; + for (int i = 0; i < n; i++) sum += cardPoints[i]; + for (int i = 0; i < len; i++) cur += cardPoints[i]; + int minv = cur; + for (int i = len; i < n; i++) { + cur = cur + cardPoints[i] - cardPoints[i - len]; + minv = min(minv, cur); + } + return sum - minv; + } +}; +``` +Python 代码: +```Python +class Solution: + def maxScore(self, cardPoints: List[int], k: int) -> int: + n, m = len(cardPoints), len(cardPoints) - k + total, cur = sum(cardPoints), sum(cardPoints[:m]) + minv = cur + for i in range(m, n): + cur = cur + cardPoints[i] - cardPoints[i - m] + minv = min(minv, cur) + return total - minv +``` +TypeScript 代码: +```TypeScript +function maxScore(cardPoints: number[], k: number): number { + const n = cardPoints.length, m = n - k; + let tot = 0, cur = 0; + for (let i = 0; i < n; i++) tot += cardPoints[i]; + for (let i = 0; i < m; i++) cur += cardPoints[i]; + let minv = cur; + for (let i = m; i < n; i++) { + cur = cur + cardPoints[i] - cardPoints[i - m]; + minv = Math.min(minv, cur); + } + return tot - minv; +}; +``` +* 时间复杂度:每个元素最多滑入和滑出窗口一次,复杂度为 $O(n)$ * 空间复杂度:$O(1)$ --- diff --git "a/LeetCode/1461-1470/1465. \345\210\207\345\211\262\345\220\216\351\235\242\347\247\257\346\234\200\345\244\247\347\232\204\350\233\213\347\263\225(\344\270\255\347\255\211).md" "b/LeetCode/1461-1470/1465. \345\210\207\345\211\262\345\220\216\351\235\242\347\247\257\346\234\200\345\244\247\347\232\204\350\233\213\347\263\225\357\274\210\344\270\255\347\255\211\357\274\211.md" similarity index 100% rename from "LeetCode/1461-1470/1465. \345\210\207\345\211\262\345\220\216\351\235\242\347\247\257\346\234\200\345\244\247\347\232\204\350\233\213\347\263\225(\344\270\255\347\255\211).md" rename to "LeetCode/1461-1470/1465. \345\210\207\345\211\262\345\220\216\351\235\242\347\247\257\346\234\200\345\244\247\347\232\204\350\233\213\347\263\225\357\274\210\344\270\255\347\255\211\357\274\211.md" diff --git "a/LeetCode/1831-1840/1833. \351\233\252\347\263\225\347\232\204\346\234\200\345\244\247\346\225\260\351\207\217\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/1831-1840/1833. \351\233\252\347\263\225\347\232\204\346\234\200\345\244\247\346\225\260\351\207\217\357\274\210\344\270\255\347\255\211\357\274\211.md" index 0dc895c4..5df93c15 100644 --- "a/LeetCode/1831-1840/1833. \351\233\252\347\263\225\347\232\204\346\234\200\345\244\247\346\225\260\351\207\217\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/1831-1840/1833. \351\233\252\347\263\225\347\232\204\346\234\200\345\244\247\346\225\260\351\207\217\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -43,10 +43,10 @@ Tony 一共有 `coins` 现金可以用于消费,他想要买尽可能多的雪 ``` 提示: -* costs.length == n -* 1 <= n <= $10^5$ -* 1 <= costs[i] <= $10^5$ -* 1 <= coins <= $10^8$ +* $costs.length = n$ +* $1 <= n <= 10^5$ +* $1 <= costs[i] <= 10^5$ +* $1 <= coins <= 10^8$ --- @@ -54,7 +54,7 @@ Tony 一共有 `coins` 现金可以用于消费,他想要买尽可能多的雪 从题面看,是一道「01 背包」问题,每个物品的成本为 $cost[i]$,价值为 $1$。 -但「01 背包」的复杂度为 $O(N* C)$,其中 $N$ 为物品数量(数量级为 $10^5$),$C$ 为背包容量(数量级为 $10^8$)。显然会 TLE。 +但「01 背包」的复杂度为 $O(N\times C)$,其中 $N$ 为物品数量(数量级为 $10^5$),$C$ 为背包容量(数量级为 $10^8$)。显然会 `TLE`。 换个思路发现,每个被选择的物品对答案的贡献都是 $1$,优先选择价格小的物品会使得我们剩余金额尽可能的多,将来能够做的决策方案也就相应变多。 @@ -100,23 +100,64 @@ Tony 一共有 `coins` 现金可以用于消费,他想要买尽可能多的雪 排序,从前往后决策,直到不能决策为止。 -代码: +Java 代码: ```Java class Solution { - public int maxIceCream(int[] cs, int t) { - int n = cs.length; - Arrays.sort(cs); + public int maxIceCream(int[] costs, int coins) { + int n = costs.length; + Arrays.sort(costs); int ans = 0; for (int i = 0; i < n; i++) { - if (t >= cs[i]) { - ans++; - t -= cs[i]; + if (coins >= costs[i]) { + ans++; coins -= costs[i]; } } return ans; } } ``` +Python 代码: +```Python +class Solution: + def maxIceCream(self, costs: List[int], coins: int) -> int: + costs.sort() + ans = 0 + for i in range(len(costs)): + if coins >= costs[i]: + ans += 1 + coins -= costs[i] + return ans +``` +C++ 代码: +```C++ +class Solution { +public: + int maxIceCream(vector& costs, int coins) { + int n = costs.size(); + sort(costs.begin(), costs.end()); + int ans = 0; + for (int i = 0; i < n; i++) { + if (coins >= costs[i]) { + ans++; coins -= costs[i]; + } + } + return ans; + } +}; +``` +TypeScript 代码: +```TypeScript +function maxIceCream(costs: number[], coins: number): number { + costs.sort((a, b) => a - b); + let ans = 0; + for (let i = 0; i < costs.length; i++) { + if (coins >= costs[i]) { + ans++; coins -= costs[i]; + } + } + return ans; +}; +``` * 时间复杂度:排序复杂度为 $O(n\log{n})$;获取答案的复杂度为 $O(n)$。整体复杂度为 $O(n\log{n})$ * 空间复杂度:排序复杂度为 $O(\log{n})$。整体复杂度为 $O(\log{n})$ diff --git "a/LeetCode/201-210/209. \351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/201-210/209. \351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" index e140deee..43add42d 100644 --- "a/LeetCode/201-210/209. \351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/201-210/209. \351\225\277\345\272\246\346\234\200\345\260\217\347\232\204\345\255\220\346\225\260\347\273\204\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -46,7 +46,7 @@ Tag : 「前缀和」、「二分」、「滑动窗口」 利用前缀和数组的「单调递增」(即具有二段性),该操作可使用「二分」来做。 -代码: +Java 代码: ```Java class Solution { public int minSubArrayLen(int t, int[] nums) { @@ -54,7 +54,7 @@ class Solution { int[] sum = new int[n + 10]; for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + nums[i - 1]; for (int i = 1; i <= n; i++) { - int s = sum[i], d = s - t; + int d = sum[i] - t; int l = 0, r = i; while (l < r) { int mid = l + r + 1 >> 1; @@ -67,6 +67,68 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + int minSubArrayLen(int t, vector& nums) { + int n = nums.size(), ans = n + 10; + vector sum(n + 10, 0); + for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + nums[i - 1]; + for (int i = 1; i <= n; i++) { + int d = sum[i] - t; + int l = 0, r = i; + while (l < r) { + int mid = (l + r + 1) >> 1; + if (sum[mid] <= d) l = mid; + else r = mid - 1; + } + if (sum[r] <= d) ans = min(ans, i - r); + } + return ans == n + 10 ? 0 : ans; + } +}; +``` +Python 代码: +```Python +class Solution: + def minSubArrayLen(self, t: int, nums: List[int]) -> int: + n, ans = len(nums), len(nums) + 10 + s = [0] * (n + 10) + for i in range(1, n + 1): + s[i] = s[i - 1] + nums[i - 1] + for i in range(1, n + 1): + d = s[i] - t + l, r = 0, i + while l < r: + mid = (l + r + 1) // 2 + if s[mid] <= d: + l = mid + else: + r = mid - 1 + if s[r] <= d: + ans = min(ans, i - r) + return 0 if ans == n + 10 else ans +``` +TypeScript 代码: +```TypeScript +function minSubArrayLen(t: number, nums: number[]): number { + let n = nums.length, ans = n + 10; + const sum = new Array(n + 10).fill(0); + for (let i = 1; i <= n; i++) sum[i] = sum[i - 1] + nums[i - 1]; + for (let i = 1; i <= n; i++) { + const d = sum[i] - t; + let l = 0, r = i; + while (l < r) { + const mid = l + r + 1 >> 1; + if (sum[mid] <= d) l = mid; + else r = mid - 1; + } + if (sum[r] <= d) ans = Math.min(ans, i - r); + } + return ans == n + 10 ? 0 : ans; +}; +``` * 时间复杂度:预处理前缀和数组的复杂度为 $O(n)$,遍历前缀和数组统计答案复杂度为 $O(n\log{n})$。整体复杂度为 $O(n\log{n})$ * 空间复杂度:$O(n)$ diff --git "a/LeetCode/2051-2060/2055. \350\234\241\347\203\233\344\271\213\351\227\264\347\232\204\347\233\230\345\255\220\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/2051-2060/2055. \350\234\241\347\203\233\344\271\213\351\227\264\347\232\204\347\233\230\345\255\220\357\274\210\344\270\255\347\255\211\357\274\211.md" index 04534d2e..03846dfd 100644 --- "a/LeetCode/2051-2060/2055. \350\234\241\347\203\233\344\271\213\351\227\264\347\232\204\347\233\230\345\255\220\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/2051-2060/2055. \350\234\241\347\203\233\344\271\213\351\227\264\347\232\204\347\233\230\345\255\220\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -55,7 +55,7 @@ Tag : 「前缀和」、「二分」 然后处理询问时的「找区间 $[a, b]$ 边缘蜡烛」操作可通过对数组「二分」来做,而「查询区间 $[c, d]$ 内的盘子数量」操作可直接查询「前缀和」数组。 -代码: +Java 代码: ```Java class Solution { public int[] platesBetweenCandles(String s, int[][] qs) { @@ -95,6 +95,125 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + vector platesBetweenCandles(string s, vector>& qs) { + vector ans(qs.size(), 0); + vector sum(s.length() + 1, 0); + vector list; + for (int i = 0; i < s.length(); i++) { + if (s[i] == '|') list.push_back(i); + sum[i + 1] = sum[i] + (s[i] == '*' ? 1 : 0); + } + if (list.empty()) return ans; + for (int i = 0; i < qs.size(); i++) { + int a = qs[i][0], b = qs[i][1]; + int c = -1, d = -1; + // 找到 a 右边最近的蜡烛 + int l = 0, r = list.size() - 1; + while (l < r) { + int mid = l + r >> 1; + if (list[mid] >= a) r = mid; + else l = mid + 1; + } + if (list[r] >= a) c = list[r]; + else continue; + // 找到 b 左边最近的蜡烛 + l = 0; r = list.size() - 1; + while (l < r) { + int mid = l + r + 1 >> 1; + if (list[mid] <= b) l = mid; + else r = mid - 1; + } + if (list[r] <= b) d = list[r]; + else continue; + if (c <= d) ans[i] = sum[d + 1] - sum[c]; + } + return ans; + } +}; +``` +Python 代码: +```Python +class Solution: + def platesBetweenCandles(self, s: str, qs: List[List[int]]) -> List[int]: + ans = [0] * len(qs) + sum_val = [0] * (len(s) + 1) + candle_positions = [i for i, char in enumerate(s) if char == '|'] + for i in range(len(s)): + sum_val[i + 1] = sum_val[i] + (s[i] == '*') + if not candle_positions: + return ans + for i in range(len(qs)): + a, b = qs[i] + c, d = -1, -1 + # 找到 a 右边最近的蜡烛 + l, r = 0, len(candle_positions) - 1 + while l < r: + mid = l + r >> 1 + if candle_positions[mid] >= a: + r = mid + else: + l = mid + 1 + if candle_positions[r] >= a: + c = candle_positions[r] + else: + continue + # 找到 b 左边最近的蜡烛 + l, r = 0, len(candle_positions) - 1 + while l < r: + mid = l + r + 1 >> 1 + if candle_positions[mid] <= b: + l = mid + else: + r = mid - 1 + if candle_positions[r] <= b: + d = candle_positions[r] + else: + continue + if c <= d: + ans[i] = sum_val[d + 1] - sum_val[c] + return ans +``` +TypeScript 代码: +```TypeScript +function platesBetweenCandles(s: string, qs: number[][]): number[] { + const ans = new Array(qs.length).fill(0); + const sum = new Array(s.length + 1).fill(0); + const list = []; + for (let i = 0; i < s.length; i++) { + if (s[i] == '|') list.push(i); + sum[i + 1] = sum[i] + (s[i] === '*' ? 1 : 0); + } + if (list.length == 0) return ans; + for (let i = 0; i < qs.length; i++) { + const a = qs[i][0], b = qs[i][1]; + let c = -1, d = -1; + // 找到 a 右边最近的蜡烛 + let l = 0, r = list.length - 1; + while (l < r) { + const mid = l + r >> 1; + if (list[mid] >= a) r = mid; + else l = mid + 1; + } + if (list[r] >= a) c = list[r]; + else continue; + // 找到 b 左边最近的蜡烛 + l = 0; r = list.length - 1; + while (l < r) { + const mid = l + r + 1 >> 1; + if (list[mid] <= b) l = mid; + else r = mid - 1; + } + if (list[r] <= b) d = list[r]; + else continue; + if (c <= d) ans[i] = sum[d + 1] - sum[c]; + } + return ans; +}; +``` * 时间复杂度:令 `s` 的长度为 $n$,`qs` 长度为 $m$。统计所有的蜡烛并存入 `list` 的复杂度为 $O(n)$;预处理前缀和数组复杂度为 $O(n)$;处理单个询问需要进行两次二分(蜡烛数量最多为 $n$),复杂度为 $O(\log{n})$,共有 $m$ 个询问需要处理,复杂度为 $O(m \times \log{n})$。整体复杂度为 $O(n + m\log{n})$ * 空间复杂度:$O(n)$ @@ -106,7 +225,7 @@ class Solution { 我们可以在预处理前缀和的同时,预处理每个位置左右最近的蜡烛下标,从而省去每次二分。 -代码: +Java 代码: ```Java class Solution { public int[] platesBetweenCandles(String s, int[][] qs) { @@ -130,6 +249,29 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + vector platesBetweenCandles(string s, vector>& qs) { + vector l(s.length(), 0), r(s.length(), 0); + vector sum(s.length() + 1, 0); + for (int i = 0, j = s.length() - 1, p = -1, q = -1; i < s.length(); i++, j--) { + if (s[i] == '|') p = i; + if (s[j] == '|') q = j; + l[i] = p; r[j] = q; + sum[i + 1] = sum[i] + (s[i] == '*' ? 1 : 0); + } + vector ans(qs.size(), 0); + for (int i = 0; i < qs.size(); i++) { + int a = qs[i][0], b = qs[i][1]; + int c = r[a], d = l[b]; + if (c != -1 && c <= d) ans[i] = sum[d + 1] - sum[c]; + } + return ans; + } +}; +``` * 时间复杂度:$O(n + m)$ * 空间复杂度:$O(n)$ diff --git "a/LeetCode/2241-2250/2246. \347\233\270\351\202\273\345\255\227\347\254\246\344\270\215\345\220\214\347\232\204\346\234\200\351\225\277\350\267\257\345\276\204\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/2241-2250/2246. \347\233\270\351\202\273\345\255\227\347\254\246\344\270\215\345\220\214\347\232\204\346\234\200\351\225\277\350\267\257\345\276\204\357\274\210\345\233\260\351\232\276\357\274\211.md" index 57f53784..c55609fb 100644 --- "a/LeetCode/2241-2250/2246. \347\233\270\351\202\273\345\255\227\347\254\246\344\270\215\345\220\214\347\232\204\346\234\200\351\225\277\350\267\257\345\276\204\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/2241-2250/2246. \347\233\270\351\202\273\345\255\227\347\254\246\344\270\215\345\220\214\347\232\204\346\234\200\351\225\277\350\267\257\345\276\204\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -123,8 +123,6 @@ class Solution { 在「定根树形 DP」题目中采用「换根树形 DP」做法,无论是从执行流程还是编码来说,都稍显“多余”(毕竟一次 `DFS` 就能以「最佳路径的最高点必然能够被处理」来得证答案的正确性),但在验证大家是否真正掌握「树形 DP」精髓来说,却有极大意义。 -使用 $f$ - 代码: ```Java diff --git "a/LeetCode/231-240/238. \351\231\244\350\207\252\350\272\253\344\273\245\345\244\226\346\225\260\347\273\204\347\232\204\344\271\230\347\247\257\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/231-240/238. \351\231\244\350\207\252\350\272\253\344\273\245\345\244\226\346\225\260\347\273\204\347\232\204\344\271\230\347\247\257\357\274\210\344\270\255\347\255\211\357\274\211.md" index 5ea09fae..6d794b4a 100644 --- "a/LeetCode/231-240/238. \351\231\244\350\207\252\350\272\253\344\273\245\345\244\226\346\225\260\347\273\204\347\232\204\344\271\230\347\247\257\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/231-240/238. \351\231\244\350\207\252\350\272\253\344\273\245\345\244\226\346\225\260\347\273\204\347\232\204\344\271\230\347\247\257\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -47,7 +47,7 @@ $$ 预处理完 `s1` 和 `s2` 之后,即可计算每个 $ans[i - 1] = s1[i - 1] \times s2[i + 1]$(`ans` 数组下标从 $0$ 开始)。 -代码: +Java 代码: ```Java class Solution { public int[] productExceptSelf(int[] nums) { @@ -62,6 +62,46 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + vector productExceptSelf(vector& nums) { + int n = nums.size(); + vector s1(n + 2, 1), s2(n + 2, 1); + for (int i = 1; i <= n; i++) s1[i] = s1[i - 1] * nums[i - 1]; + for (int i = n; i >= 1; i--) s2[i] = s2[i + 1] * nums[i - 1]; + vector ans(n); + for (int i = 1; i <= n; i++) ans[i - 1] = s1[i - 1] * s2[i + 1]; + return ans; + } +}; +``` +Python 代码: +```Python +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + n = len(nums) + s1, s2 = [1] * (n + 2), [1] * (n + 2) + for i in range(1, n + 1): + s1[i] = s1[i - 1] * nums[i - 1] + for i in range(n, 0, -1): + s2[i] = s2[i + 1] * nums[i - 1] + ans = [s1[i - 1] * s2[i + 1] for i in range(1, n + 1)] + return ans +``` +TypeScript 代码: +```TypeScript +function productExceptSelf(nums: number[]): number[] { + const n = nums.length; + const s1 = new Array(n + 2).fill(1), s2 = new Array(n + 2).fill(1); + for (let i = 1; i <= n; i++) s1[i] = s1[i - 1] * nums[i - 1]; + for (let i = n; i >= 1; i--) s2[i] = s2[i + 1] * nums[i - 1]; + const ans = new Array(n); + for (let i = 1; i <= n; i++) ans[i - 1] = s1[i - 1] * s2[i + 1]; + return ans; +}; +``` * 时间复杂度:$O(n)$ * 空间复杂度:$O(n)$ @@ -73,7 +113,7 @@ class Solution { 这样很好处理,按照我们解法一的思路,将两部分分开算即可:建立 `ans` 数组,先从前往后遍历 `nums`,计算每个 $ans[i]$ 前缀乘值部分,再从后往前遍历 `nums`,计算每个 $ans[i]$ 后缀乘值的部分,两部分相乘即是最终的 $ans[i]$。 -代码: +Java 代码: ```Java class Solution { public int[] productExceptSelf(int[] nums) { @@ -89,6 +129,53 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + vector productExceptSelf(vector& nums) { + int n = nums.size(); + vector ans(n, 1); + for (int i = 1, j = 1; i <= n; i++) { + ans[i - 1] = j; j *= nums[i - 1]; + } + for (int i = n, j = 1; i >= 1; i--) { + ans[i - 1] *= j; j *= nums[i - 1]; + } + return ans; + } +}; +``` +Python 代码: +```Python +class Solution: + def productExceptSelf(self, nums: List[int]) -> List[int]: + n = len(nums) + ans = [1] * n + j = 1 + for i in range(1, n + 1): + ans[i - 1] *= j + j *= nums[i - 1] + j = 1 + for i in range(n, 0, -1): + ans[i - 1] *= j + j *= nums[i - 1] + return ans +``` +TypeScript 代码: +```TypeScript +function productExceptSelf(nums: number[]): number[] { + const n = nums.length; + const ans = new Array(n).fill(1); + for (let i = 1, j = 1; i <= n; i++) { + ans[i - 1] *= j; j *= nums[i - 1]; + } + for (let i = n, j = 1; i >= 1; i--) { + ans[i - 1] *= j; j *= nums[i - 1]; + } + return ans; +}; +``` * 时间复杂度:$O(n)$ * 空间复杂度:$O(1)$ diff --git "a/LeetCode/2471-2480/2477. \345\210\260\350\276\276\351\246\226\351\203\275\347\232\204\346\234\200\345\260\221\346\262\271\350\200\227\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/2471-2480/2477. \345\210\260\350\276\276\351\246\226\351\203\275\347\232\204\346\234\200\345\260\221\346\262\271\350\200\227\357\274\210\344\270\255\347\255\211\357\274\211.md" new file mode 100644 index 00000000..172b3549 --- /dev/null +++ "b/LeetCode/2471-2480/2477. \345\210\260\350\276\276\351\246\226\351\203\275\347\232\204\346\234\200\345\260\221\346\262\271\350\200\227\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -0,0 +1,233 @@ +### 题目描述 + +这是 LeetCode 上的 **[2477. 到达首都的最少油耗](https://leetcode.cn/problems/minimum-fuel-cost-to-report-to-the-capital/solutions/2554316/gong-shui-san-xie-zhu-bu-jiang-jie-zui-d-25qs/)** ,难度为 **中等**。 + +Tag : 「DFS」 + + + +给你一棵 `n` 个节点的树(一个无向、连通、无环图),每个节点表示一个城市,编号从 `0` 到 `n - 1`,且恰好有 `n - 1` 条路。 + +`0` 是首都。给你一个二维整数数组 `roads`,其中 $roads[i] = [a_{i}, b_{i}]$ ,表示城市 $a_{i}$ 和 $b_{i}$ 之间有一条 双向路 。 + +每个城市里有一个代表,他们都要去首都参加一个会议。 + +每座城市里有一辆车。给你一个整数 `seats` 表示每辆车里面座位的数目。 + +城市里的代表可以选择乘坐所在城市的车,或者乘坐其他城市的车。相邻城市之间一辆车的油耗是一升汽油。 + +请你返回到达首都最少需要多少升汽油。 + +示例 1: +![](https://assets.leetcode.com/uploads/2022/09/22/a4c380025e3ff0c379525e96a7d63a3.png) +``` +输入:roads = [[0,1],[0,2],[0,3]], seats = 5 + +输出:3 + +解释: +- 代表 1 直接到达首都,消耗 1 升汽油。 +- 代表 2 直接到达首都,消耗 1 升汽油。 +- 代表 3 直接到达首都,消耗 1 升汽油。 +最少消耗 3 升汽油。 +``` +示例 2: +![](https://assets.leetcode.com/uploads/2022/11/16/2.png) +``` +输入:roads = [[3,1],[3,2],[1,0],[0,4],[0,5],[4,6]], seats = 2 + +输出:7 + +解释: +- 代表 2 到达城市 3 ,消耗 1 升汽油。 +- 代表 2 和代表 3 一起到达城市 1 ,消耗 1 升汽油。 +- 代表 2 和代表 3 一起到达首都,消耗 1 升汽油。 +- 代表 1 直接到达首都,消耗 1 升汽油。 +- 代表 5 直接到达首都,消耗 1 升汽油。 +- 代表 6 到达城市 4 ,消耗 1 升汽油。 +- 代表 4 和代表 6 一起到达首都,消耗 1 升汽油。 +最少消耗 7 升汽油。 +``` +示例 3: +![](https://assets.leetcode.com/uploads/2022/09/27/efcf7f7be6830b8763639cfd01b690a.png) +``` +输入:roads = [], seats = 1 + +输出:0 + +解释:没有代表需要从别的城市到达首都。 +``` + +提示: +* $1 <= n <= 105$ +* $roads.length = n - 1$ +* $roads[i].length = 2$ +* $0 <= a_{i}, b_{i} < n$ +* $a_{i} != b_{i}$ +* `roads` 表示一棵合法的树。 +* $1 <= seats <= 10^5$ + +--- + +### DFS + +将双向图看作是以节点 `0` 为根的有向树,从每个节点出发往 `0` 前行,可看作是自底向上的移动过程。 + +![image.png](https://pic.leetcode.cn/1701743655-EZFMCm-image.png) + +当 `seats = 1` 时,每个节点前往 `0` 的过程相互独立,总油耗为每节点到 `0` 的最短距离之和。 + +当 `seats` 不为 `1` 时,考虑组成顺风车,此时总的油耗不该超过 `seats = 1` 的情况。 + +不难发现,**只有「深度大的节点,在前往 `0` 过程中,搭乘深度小顺风车」可减少油耗**(例如在上图节点 `3` 在经过节点 `1` 时搭乘顺风车,可与节点 `1` 合计使用一份油耗前往到 `0`),否则如果是深度小的节点先往深度大的节点走,再一同前往 `0`,会额外多经过某些边,产生不必要的油耗。 + +考虑组成顺风车时,总油耗该如何计算。 + +基于上述分析,无论 `seats` 是否为 $1$(是否组成顺风车),每个节点前往 `0` 的路径总是不变,即经过的边固定不变,必然是自底向上。 + +因此我们可统计每条边会被多少个节点经过,通过 `DFS` 统计「以每个节点为根时,子树的节点数量」即是经过该节点往上的边。 + +![image.png](https://pic.leetcode.cn/1701743638-UXsdes-image.png) + +Java 代码: +```Java +class Solution { + int N = 100010, M = 2 * N, idx = 0; + int[] he = new int[N], e = new int[M], ne = new int[M]; + void add(int a, int b) { + e[idx] = b; + ne[idx] = he[a]; + he[a] = idx++; + } + long ans = 0; + public long minimumFuelCost(int[][] roads, int seats) { + int n = roads.length + 1; + Arrays.fill(he, -1); + for (int[] r : roads) { + int a = r[0], b = r[1]; + add(a, b); add(b, a); + } + dfs(0, -1, seats); + return ans; + } + int dfs(int u, int fa, int t) { + int cnt = 1; + for (int i = he[u]; i != -1; i = ne[i]) { + int j = e[i]; + if (j == fa) continue; + cnt += dfs(j, u, t); + } + if (u != 0) ans += Math.ceil(cnt * 1.0 / t); + return cnt; + } +} +``` +C++ 代码: +```C++ +class Solution { +public: + int N = 100010, M = 2 * N, idx = 0; + int he[100010], e[200020], ne[200020]; + long long ans = 0; + void add(int a, int b) { + e[idx] = b; + ne[idx] = he[a]; + he[a] = idx++; + } + long long minimumFuelCost(vector>& roads, int seats) { + int n = roads.size() + 1; + memset(he, -1, sizeof(he)); + for (auto& r : roads) { + int a = r[0], b = r[1]; + add(a, b); add(b, a); + } + dfs(0, -1, seats); + return ans; + } + int dfs(int u, int fa, int t) { + int cnt = 1; + for (int i = he[u]; i != -1; i = ne[i]) { + int j = e[i]; + if (j == fa) continue; + cnt += dfs(j, u, t); + } + if (u != 0) ans += ceil(cnt * 1.0 / t); + return cnt; + } +}; +``` +Python 代码: +```Python +class Solution: + def minimumFuelCost(self, roads: List[List[int]], seats: int) -> int: + n, m, ans = len(roads) + 1, len(roads) * 2 + 1, 0 + he, e, ne, idx = [-1] * n, [0] * m, [0] * m, 0 + + def add(a, b): + nonlocal idx + e[idx] = b + ne[idx] = he[a] + he[a] = idx + idx += 1 + + def dfs(u, fa, t): + nonlocal ans + cnt = 1 + i = he[u] + while i != -1: + j, i = e[i], ne[i] + if j == fa: continue + cnt += dfs(j, u, t) + if u != 0: + ans += math.ceil(cnt * 1.0 / t) + return cnt + + for a, b in roads: + add(a, b) + add(b, a) + dfs(0, -1, seats) + return ans +``` +TypeScript 代码: +```TypeScript +function minimumFuelCost(roads: number[][], seats: number): number { + const n = roads.length + 1, m = n * 2; + const he = Array(n).fill(-1), e = Array(m).fill(0), ne = Array(m).fill(0); + let ans = 0, idx = 0; + const add = function(a: number, b: number) { + e[idx] = b; + ne[idx] = he[a]; + he[a] = idx++; + } + const dfs = function(u: number, fa: number, t: number): number { + let cnt = 1; + for (let i = he[u]; i != -1; i = ne[i]) { + const j = e[i]; + if (j == fa) continue; + cnt += dfs(j, u, t); + } + if (u != 0) ans += Math.ceil(cnt * 1.0 / t); + return cnt; + } + for (const [a, b] of roads) { + add(a, b); add(b, a); + } + dfs(0, -1, seats); + return ans; +}; +``` +* 时间复杂度:建图复杂度为 $O(n)$;递归统计每个子树节点数量并计算油耗复杂度 $O(n)$;整体复杂度为 $O(n)$ +* 空间复杂度:$O(n)$ + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.2477` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 + diff --git "a/LeetCode/2661-2670/2661. \346\211\276\345\207\272\345\217\240\346\266\202\345\205\203\347\264\240\357\274\210\347\256\200\345\215\225\357\274\211.md" "b/LeetCode/2661-2670/2661. \346\211\276\345\207\272\345\217\240\346\266\202\345\205\203\347\264\240\357\274\210\347\256\200\345\215\225\357\274\211.md" new file mode 100644 index 00000000..704fd184 --- /dev/null +++ "b/LeetCode/2661-2670/2661. \346\211\276\345\207\272\345\217\240\346\266\202\345\205\203\347\264\240\357\274\210\347\256\200\345\215\225\357\274\211.md" @@ -0,0 +1,148 @@ +### 题目描述 + +这是 LeetCode 上的 **[2661. 找出叠涂元素](https://leetcode.cn/problems/first-completely-painted-row-or-column/solutions/2549034/gong-shui-san-xie-chang-gui-ha-xi-biao-y-jkxa/)** ,难度为 **中等**。 + +Tag : 「模拟」、「哈希表」、「计数」 + + + +给你一个下标从 $0$ 开始的整数数组 `arr` 和一个 $m \times n$ 的整数矩阵 `mat`。 + +`arr` 和 `mat` 都包含范围 $[1,m \times n]$ 内的所有整数。 + +从下标 $0$ 开始遍历 `arr` 中的每个下标 `i` ,并将包含整数 `arr[i]` 的 `mat` 单元格涂色。 + +请你找出 `arr` 中在 `mat` 的某一行或某一列上都被涂色且下标最小的元素,并返回其下标 $i$ 。 + +示例 1: +![](https://assets.leetcode.com/uploads/2023/01/18/grid1.jpg) + +``` +输入:arr = [1,3,4,2], mat = [[1,4],[2,3]] + +输出:2 + +解释:遍历如上图所示,arr[2] 在矩阵中的第一行或第二列上都被涂色。 +``` +示例 2: +![](https://assets.leetcode.com/uploads/2023/01/18/grid2.jpg) +``` +image explanation for example 2 + +输入:arr = [2,8,7,4,1,3,5,6,9], mat = [[3,2,5],[1,4,6],[8,7,9]] + +输出:3 + +解释:遍历如上图所示,arr[3] 在矩阵中的第二列上都被涂色。 +``` + +提示: +* $m = mat.length$ +* $n = mat[i].length$ +* $arr.length = m \times n$ +* $1 <= m, n <= 10^5$ +* $1 <= m \times n <= 105$ +* $1 <= arr[i], mat[r][c] <= m \times n$ +* `arr` 中的所有整数互不相同 +* `mat` 中的所有整数互不相同 + +--- + +### 哈希表 + +利用 `mat` 的数值各不相同,先使用「哈希表」对 `mat` 进行转存,以 $mat[i][j]$ 为键,$(i, j)$ 为值,方便后续快速查询某个值所在位置。 + +创建数组 `c1` 和 `c2`,分别记录某行某列有多少单元格被涂色,如 `c1[x] = a` 代表第 $x$ 行被涂色单元格数量为 $a$ 个,`c2[y] = b` 代表第 $y$ 列被涂色单元格数量为 $b$ 个。 + +遍历所有的 $arr[i]$,查询到 $arr[i]$ 的所在位置 $(x, y)$ 后,更新 `c1` 和 `c2`,若某行或某列被完全涂色,返回当前下标。 + +Java 代码: + +```Java +class Solution { + public int firstCompleteIndex(int[] arr, int[][] mat) { + int n = mat.length, m = mat[0].length; + Map map = new HashMap<>(); + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + map.put(mat[i][j], new int[]{i, j}); + } + } + int[] c1 = new int[n], c2 = new int[m]; + for (int i = 0; i < n * m; i++) { + int[] info = map.get(arr[i]); + int x = info[0], y = info[1]; + if (++c1[x] == m || ++c2[y] == n) return i; + } + return -1; // never + } +} +``` +C++ 代码: +```C++ +class Solution { +public: + int firstCompleteIndex(vector& arr, vector>& mat) { + int n = mat.size(), m = mat[0].size(); + unordered_map> map; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + map[mat[i][j]] = make_pair(i, j); + } + } + vector c1(n), c2(m); + for (int i = 0; i < n * m; i++) { + pair info = map[arr[i]]; + int x = info.first, y = info.second; + if (++c1[x] == m || ++c2[y] == n) return i; + } + return -1; // never + } +}; +``` +Python 代码: +```Python +class Solution: + def firstCompleteIndex(self, arr: List[int], mat: List[List[int]]) -> int: + n, m = len(mat), len(mat[0]) + mapping = {mat[i][j]: (i, j) for i in range(n) for j in range(m)} + c1, c2 = [0] * n, [0] * m + for i in range(n * m): + x, y = mapping[arr[i]] + c1[x], c2[y] = c1[x] + 1, c2[y] + 1 + if c1[x] == m or c2[y] == n: return i + return -1 # never +``` +TypeScript 代码: +```TypeScript +function firstCompleteIndex(arr: number[], mat: number[][]): number { + const n = mat.length, m = mat[0].length; + const map: { [key: number]: [number, number] } = {}; + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + map[mat[i][j]] = [i, j]; + } + } + const c1 = new Array(n).fill(0), c2 = new Array(m).fill(0); + for (let i = 0; i < n * m; i++) { + const [x, y] = map[arr[i]]; + if (++c1[x] == m || ++c2[y] === n) return i; + } + return -1; // never +}; +``` +* 时间复杂度:$O(n \times m)$ +* 空间复杂度:$O(n \times m)$ + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.2661` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 + diff --git "a/LeetCode/811-820/816. \346\250\241\347\263\212\345\235\220\346\240\207\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/811-820/816. \346\250\241\347\263\212\345\235\220\346\240\207\357\274\210\344\270\255\347\255\211\357\274\211.md" index bfe13c9c..f939747d 100644 --- "a/LeetCode/811-820/816. \346\250\241\347\263\212\345\235\220\346\240\207\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/811-820/816. \346\250\241\347\263\212\345\235\220\346\240\207\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -125,7 +125,7 @@ function ambiguousCoordinates(_s: string): string[] { } ``` Python 代码: -```Python3 [] +```Python3 class Solution: def ambiguousCoordinates(self, _s: str) -> List[str]: def search(s, start, end): diff --git "a/LeetCode/831-840/834. \346\240\221\344\270\255\350\267\235\347\246\273\344\271\213\345\222\214\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/831-840/834. \346\240\221\344\270\255\350\267\235\347\246\273\344\271\213\345\222\214\357\274\210\345\233\260\351\232\276\357\274\211.md" index c3f60bdb..6c30c72f 100644 --- "a/LeetCode/831-840/834. \346\240\221\344\270\255\350\267\235\347\246\273\344\271\213\345\222\214\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/831-840/834. \346\240\221\344\270\255\350\267\235\347\246\273\344\271\213\345\222\214\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -166,6 +166,55 @@ class Solution { } } ``` +C++ 代码: +```C++ +class Solution { +public: + int N = 30010, M = 60010, idx = 0, n; + int he[30010], e[60010], ne[60010]; + int f[30010], c[30010], g[30010]; + void add(int a, int b) { + e[idx] = b; + ne[idx] = he[a]; + he[a] = idx++; + } + vector sumOfDistancesInTree(int _n, vector>& es) { + n = _n; + memset(he, -1, sizeof(he)); + for (auto& e : es) { + int a = e[0], b = e[1]; + add(a, b); + add(b, a); + } + dfs1(0, -1); + dfs2(0, -1); + vector ans(n); + for (int i = 0; i < n; i++) ans[i] = f[i] + g[i]; + return ans; + } + vector dfs1(int u, int fa) { + int tot = 0, cnt = 0; + for (int i = he[u]; i != -1; i = ne[i]) { + int j = e[i]; + if (j == fa) continue; + vector next = dfs1(j, u); + tot += next[0] + next[1] + 1; + cnt += next[1] + 1; + } + f[u] = tot; c[u] = cnt; + return {tot, cnt}; + } + void dfs2(int u, int fa) { + for (int i = he[u]; i != -1; i = ne[i]) { + int j = e[i]; + if (j == fa) continue; + g[j] += g[u] + n - 1 - c[u]; + g[j] += f[u] - f[j] - c[j] + c[u] - 1 - c[j]; + dfs2(j, u); + } + } +}; +``` * 时间复杂度:$O(n)$ * 空间复杂度:$O(n)$