From c0bcc285271e041252c37f651c7395cb4f87ef0f Mon Sep 17 00:00:00 2001 From: AC_Oier Date: Wed, 11 May 2022 10:57:20 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8style:=20Bulk=20processing=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\344\272\214\345\217\211\346\240\221.md" | 1 + ...10\345\233\260\351\232\276\357\274\211.md" | 6 +- ...10\345\233\260\351\232\276\357\274\211.md" | 8 +- ...10\344\270\255\347\255\211\357\274\211.md" | 9 +- ...10\344\270\255\347\255\211\357\274\211.md" | 102 ++++++++++++++++++ ...10\344\270\255\347\255\211\357\274\211.md" | 14 +-- 6 files changed, 120 insertions(+), 20 deletions(-) create mode 100644 "LeetCode/441-450/449. \345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\357\274\210\344\270\255\347\255\211\357\274\211.md" 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 befd0eb9..1ea11dc5 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" @@ -4,6 +4,7 @@ | [240. 搜索二维矩阵 II](https://leetcode-cn.com/problems/search-a-2d-matrix-ii/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/search-a-2d-matrix-ii/solution/gong-shui-san-xie-yi-ti-shuang-jie-er-fe-y1ns/) | 中等 | 🤩🤩🤩🤩 | | [297. 二叉树的序列化与反序列化](https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/) | [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/) | 困难 | 🤩🤩🤩🤩🤩 | | [437. 路径总和 III](https://leetcode-cn.com/problems/path-sum-iii/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/path-sum-iii/solution/gong-shui-san-xie-yi-ti-shuang-jie-dfs-q-usa7/) | 中等 | 🤩🤩🤩🤩 | +| [449. 序列化和反序列化二叉搜索树](https://leetcode.cn/problems/serialize-and-deserialize-bst/) | [LeetCode 题解链接](https://leetcode.cn/problems/serialize-and-deserialize-bst/solution/by-ac_oier-ncwn/) | 中等 | 🤩🤩🤩🤩 | | [563. 二叉树的坡度](https://leetcode-cn.com/problems/binary-tree-tilt/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/binary-tree-tilt/solution/gong-shui-san-xie-jian-dan-er-cha-shu-di-ekz4/) | 简单 | 🤩🤩🤩🤩 | | [606. 根据二叉树创建字符串](https://leetcode-cn.com/problems/construct-string-from-binary-tree/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/construct-string-from-binary-tree/solution/by-ac_oier-i2sk/) | 简单 | 🤩🤩🤩🤩 | | [653. 两数之和 IV - 输入 BST](https://leetcode-cn.com/problems/two-sum-iv-input-is-a-bst/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/two-sum-iv-input-is-a-bst/solution/by-ac_oier-zr4o/) | 简单 | 🤩🤩🤩🤩 | diff --git "a/LeetCode/1721-1730/1728. \347\214\253\345\222\214\350\200\201\351\274\240 II\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/1721-1730/1728. \347\214\253\345\222\214\350\200\201\351\274\240 II\357\274\210\345\233\260\351\232\276\357\274\211.md" index dc54303b..ad49d183 100644 --- "a/LeetCode/1721-1730/1728. \347\214\253\345\222\214\350\200\201\351\274\240 II\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/1721-1730/1728. \347\214\253\345\222\214\350\200\201\351\274\240 II\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -82,7 +82,7 @@ Tag : 「博弈论」、「动态规划」、「记忆化搜索」 当时在 [(题解) 913. 猫和老鼠](https://leetcode.cn/problems/cat-and-mouse/solution/gong-shui-san-xie-dong-tai-gui-hua-yun-y-0bx1/) 没能证出来更小 $K$ 值(回合数)的正确性,用的 $2n^2$ 做的 ,其余题解说 $2 n$ 合法,后来也被证实是错误的。 -对于本题如果用相同的分析思路,状态数多达 $8 * 8 * 8 * 8 * 2 = 8192$ 种,题目很贴心调整了规则为 $1000$ 步以内为猫获胜,但证明 $K$ 的理论上界仍是困难(上次分析不出来,这次压根不想分析 +对于本题如果用相同的分析思路,状态数多达 $8 \times 8 \times 8 \times 8 \times 2 = 8192$ 种,题目很贴心调整了规则为 $1000$ 步以内为猫获胜,但证明 $K$ 的理论上界仍是困难(上次分析不出来,这次压根不想分析 如果忽略 $K$ 值分析,代码还是很好写的:定义函数 `int dfs(int x, int y, int p, int q, int k)` 并配合记忆化搜索,其中鼠位于 $(x, y)$,猫位于 $(p, q)$,当前轮数为 $k$(由 $k$ 的奇偶性可知是谁的回合)。 @@ -151,8 +151,8 @@ class Solution { } } ``` -* 时间复杂度:令 $n$ 和 $m$ 分别为矩阵的长宽,最长移动距离为 $L$,复杂度为 $O(n^2 * m^2 * 1000 * 4 * L)$ -* 空间复杂度:$O(n^2 * m^2 * 1000)$ +* 时间复杂度:令 $n$ 和 $m$ 分别为矩阵的长宽,最长移动距离为 $L$,复杂度为 $O(n^2 \times m^2 \times 1000 \times 4 \times L)$ +* 空间复杂度:$O(n^2 \times m^2 \times 1000)$ --- diff --git "a/LeetCode/1751-1760/1751. \346\234\200\345\244\232\345\217\257\344\273\245\345\217\202\345\212\240\347\232\204\344\274\232\350\256\256\346\225\260\347\233\256 II\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/1751-1760/1751. \346\234\200\345\244\232\345\217\257\344\273\245\345\217\202\345\212\240\347\232\204\344\274\232\350\256\256\346\225\260\347\233\256 II\357\274\210\345\233\260\351\232\276\357\274\211.md" index fc248be6..f246bb96 100644 --- "a/LeetCode/1751-1760/1751. \346\234\200\345\244\232\345\217\257\344\273\245\345\217\202\345\212\240\347\232\204\344\274\232\350\256\256\346\225\260\347\233\256 II\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/1751-1760/1751. \346\234\200\345\244\232\345\217\257\344\273\245\345\217\202\345\212\240\347\232\204\344\274\232\350\256\256\346\225\260\347\233\256 II\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -105,8 +105,8 @@ class Solution { } } ``` -* 时间复杂度:排序复杂度为 $O(n\log{n})$,循环 `n` 个事件,每次循环需要往回找一个事件,复杂度为 $O(n)$,并更新 `k` 个状态,复杂度为 $O(k)$,因此转移的复杂度为 $O(n * (n + k))$;总的复杂度为 $O(n * (n + k + \log{n}))$ -* 空间复杂度:$O(n * k)$ +* 时间复杂度:排序复杂度为 $O(n\log{n})$,循环 `n` 个事件,每次循环需要往回找一个事件,复杂度为 $O(n)$,并更新 `k` 个状态,复杂度为 $O(k)$,因此转移的复杂度为 $O(n \times (n + k))$;总的复杂度为 $O(n \times (n + k + \log{n}))$ +* 空间复杂度:$O(n \times k)$ --- @@ -145,8 +145,8 @@ class Solution { } } ``` -* 时间复杂度:排序复杂度为 $O(n\log{n})$,循环 `n` 个事件,每次循环需要往回找一个事件,复杂度为 $O(\log{n})$,并更新 `k` 个状态,复杂度为 $O(k)$,因此转移的复杂度为 $O(n * (\log{n} + k))$;总的复杂度为 $O(n * (k + \log{n}))$ -* 空间复杂度:$O(n * k)$ +* 时间复杂度:排序复杂度为 $O(n\log{n})$,循环 `n` 个事件,每次循环需要往回找一个事件,复杂度为 $O(\log{n})$,并更新 `k` 个状态,复杂度为 $O(k)$,因此转移的复杂度为 $O(n \times (\log{n} + k))$;总的复杂度为 $O(n \times (k + \log{n}))$ +* 空间复杂度:$O(n \times k)$ --- diff --git "a/LeetCode/2021-2030/2028. \346\211\276\345\207\272\347\274\272\345\244\261\347\232\204\350\247\202\346\265\213\346\225\260\346\215\256\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/2021-2030/2028. \346\211\276\345\207\272\347\274\272\345\244\261\347\232\204\350\247\202\346\265\213\346\225\260\346\215\256\357\274\210\344\270\255\347\255\211\357\274\211.md" index 81a92766..f3165ccb 100644 --- "a/LeetCode/2021-2030/2028. \346\211\276\345\207\272\347\274\272\345\244\261\347\232\204\350\247\202\346\265\213\346\225\260\346\215\256\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/2021-2030/2028. \346\211\276\345\207\272\347\274\272\345\244\261\347\232\204\350\247\202\346\265\213\346\225\260\346\215\256\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -62,12 +62,13 @@ $k$ 个数字的 平均值 为这些数字求和后再除以 $k$ 。 根据题意,我们需要构造长度为 $n$ 的序列 $ans$,使得 $ans$ 和 $rolls$ 并集的平均值为 $mean$。 -由于最终的平均值 $mean$ 已知,我们可以直接算得两序列之和为 $t = (m + n) * mean$。 +由于最终的平均值 $mean$ 已知,我们可以直接算得两序列之和为 $t = (m + n) \times mean$。 -使用 $t$ 减去 $\sum_{i = 0}^{m}rolls[i]$ 可得 $\sum_{i = 0}^{n}ans[i]$。我们知道一个长度为 $n$ 的有效序列的元素和范围为 $[n, 6 * n]$(骰子编号为 $[1, 6]$),根据 $\sum_{i = 0}^{m}rolls[i]$ 与 $[n, 6 * n]$ 关系进行分情况讨论: +使用 $t$ 减去 $$\sum_{i = 0}^{m}rolls[i]$$ 可得 $$\sum_{i = 0}^{n}ans[i]$$。我们知道一个长度为 $n$ 的有效序列的元素和范围为 $[n, 6 \times n]$(骰子编号为 $[1, 6]$),根据 $\sum_{i = 0}^{m}rolls[i]$ 与 $[n, 6 \times n]$ 关系进行分情况讨论: -* 如果 $\sum_{i = 0}^{n}ans[i]$ 不落在 $[n, 6 * n]$ 范围内,无解,直接返回空数组; -* 如果 $\sum_{i = 0}^{n}ans[i]$ 落在 $[n, 6 * n]$ 范围内,有解,此时尝试构造一个合法的 $ans$ : 起始使用 $\left \lfloor \frac{\sum_{i = 0}^{n}ans[i]}{n} \right \rfloor$ 填充 $ans$,若 $\left \lfloor \frac{\sum_{i = 0}^{n}ans[i]}{n} \right \rfloor * n < \sum_{i = 0}^{n}ans[i]$,计算两者差异值 $d$,并尝试将 $d$ 分摊到前 $d$ 个 $ans[i]$ 上(该过程一定可以顺利进行)。 +* 如果 $$\sum_{i = 0}^{n}ans[i]$$ 不落在 $[n, 6 \times n]$ 范围内,无解,直接返回空数组; + +* 如果 $$\sum_{i = 0}^{m} rool[i]$$ 落在 $[n, 6 \times n]$ 范围内,有解,此时尝试构造一个合法的 $ans$ : 起始使用 $$\left \lfloor \frac{\sum_{i = 0}^{n}ans[i]}{n} \right \rfloor$$ 填充 $ans$,若 $$\left \lfloor \frac{\sum_{i = 0}^{n}ans[i]}{n} \right \rfloor \times n < \sum_{i = 0}^{n}ans[i]$$,计算两者差异值 $d$,并尝试将 $d$ 分摊到前 $d$ 个 $ans[i]$ 上(该过程一定可以顺利进行)。 代码: ```Java diff --git "a/LeetCode/441-450/449. \345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/441-450/449. \345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\357\274\210\344\270\255\347\255\211\357\274\211.md" new file mode 100644 index 00000000..0e039c4f --- /dev/null +++ "b/LeetCode/441-450/449. \345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -0,0 +1,102 @@ +### 题目描述 + +这是 LeetCode 上的 **[449. 序列化和反序列化二叉搜索树](https://leetcode.cn/problems/serialize-and-deserialize-bst/solution/by-ac_oier-ncwn/)** ,难度为 **中等**。 + +Tag : 「前序遍历」、「BST」 + + + +序列化是将数据结构或对象转换为一系列位的过程,以便它可以存储在文件或内存缓冲区中,或通过网络连接链路传输,以便稍后在同一个或另一个计算机环境中重建。 + +设计一个算法来序列化和反序列化 二叉搜索树 。 对序列化/反序列化算法的工作方式没有限制。 您只需确保二叉搜索树可以序列化为字符串,并且可以将该字符串反序列化为最初的二叉搜索树。 + +编码的字符串应尽可能紧凑。 + +示例 1: +``` +输入:root = [2,1,3] + +输出:[2,1,3] +``` +示例 2: +``` +输入:root = [] + +输出:[] +``` + +提示: +* 树中节点数范围是 $[0, 10^4]$ +* $0 <= Node.val <= 10^4$ +* 题目数据 保证 输入的树是一棵二叉搜索树。 + +--- + +### BST 特性(前序遍历) + +实现上,我们可以忽略「BST」这一条件,使用「BFS」或者「直接充当满二叉树」来序列化和反序列化。 + +但由于点的数量是 $1e4$,最坏情况下是当 BST 成链时,会有较大的空间浪费。 + +因此,一种较为紧凑的序列化/反序列化的方式是利用「前序遍历 + BST 特性」: + +* 序列化:对 BST 进行「前序遍历」,并跳过空节点,节点值通过 `,` 进行分割,假设最终序列化出来的字符串是 `s`。 + 之所以使用「前序遍历」是为了方便反序列化:首先对于某个子树而言,其必然是连续存储,也就是必然能够使用 $s[l,r]$ 所表示处理,同时首位元素必然是该子树的头结点; + +* 反序列化:将 `s` 根据分隔符 `,` 进行分割,假设分割后数组 `ss` 长度为 $n$,那么 $ss[0, n - 1]$ 代表完整的子树,我们可以利用「二叉树」特性递归构建,设计递归函数 `TreeNode dfs2(int l, int r, Sring[] ss)`,其含义为利用 $ss[l, r]$ 连续段构造二叉树,并返回头结点: + 1. $ss[l]$ 为头结点,其值为 $t$,在 $[l, r]$ 范围内找到第一个比 $t$ 大的位置 $j$: + 2. $ss[l]$ 的左子树的所有值均比 $t$ 小,且在 `s` 中连续存储,我们可以递归处理 $[l + 1, j - 1]$ 构建左子树; + 3. $ss[l]$ 的右子树的所有值均比 $t$ 大,且在 `s` 中连续存储,我们可以递归处理 $[j, r]$ 构建右子树。 + +代码: +```Java +public class Codec { + public String serialize(TreeNode root) { + if (root == null) return null; + List list = new ArrayList<>(); + dfs1(root, list); + int n = list.size(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < n; i++) { + sb.append(list.get(i)); + if (i != n - 1) sb.append(","); + } + return sb.toString(); + } + void dfs1(TreeNode root, List list) { + if (root == null) return ; + list.add(String.valueOf(root.val)); + dfs1(root.left, list); + dfs1(root.right, list); + } + public TreeNode deserialize(String s) { + if (s == null) return null; + String[] ss = s.split(","); + return dfs2(0, ss.length - 1, ss); + } + TreeNode dfs2(int l, int r, String[] ss) { + if (l > r) return null; + int j = l + 1, t = Integer.parseInt(ss[l]); + TreeNode ans = new TreeNode(t); + while (j <= r && Integer.parseInt(ss[j]) <= t) j++; + ans.left = dfs2(l + 1, j - 1, ss); + ans.right = dfs2(j, r, ss); + return ans; + } +} +``` +* 时间复杂度:令节点数量为 $n$,复杂度为 $O(n)$ +* 空间复杂度:$O(n)$ + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.449` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 + diff --git "a/LeetCode/71-80/80. \345\210\240\351\231\244\346\234\211\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271 II\357\274\210\344\270\255\347\255\211\357\274\211.md" "b/LeetCode/71-80/80. \345\210\240\351\231\244\346\234\211\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271 II\357\274\210\344\270\255\347\255\211\357\274\211.md" index e17353fc..279e1dae 100644 --- "a/LeetCode/71-80/80. \345\210\240\351\231\244\346\234\211\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271 II\357\274\210\344\270\255\347\255\211\357\274\211.md" +++ "b/LeetCode/71-80/80. \345\210\240\351\231\244\346\234\211\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271 II\357\274\210\344\270\255\347\255\211\357\274\211.md" @@ -6,12 +6,10 @@ Tag : 「双指针」 -给你一个有序数组 nums ,请你「原地」删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度。 +给你一个有序数组 `nums` ,请你「原地」删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度。 不要使用额外的数组空间,你必须「原地」修改输入数组 并在使用 $O(1)$ 额外空间的条件下完成。 -  - 说明: 为什么返回数值是整数,但输出的答案是数组呢? @@ -50,9 +48,9 @@ for (int i = 0; i < len; i++) { 提示: -* 1 <= nums.length <= 3 * $10^4$ -* -$10^4$ <= nums[i] <= $10^4$ -* nums 已按升序排列 +* $1 <= nums.length <= 3 \times 10^4$ +* $-10^4 <= nums[i] <= 10^4$ +* `nums` 已按升序排列 --- @@ -65,9 +63,7 @@ for (int i = 0; i < len; i++) { * 由于是保留 `k` 个相同数字,**对于前 `k` 个数字,我们可以直接保留** * 对于后面的任意数字,能够保留的前提是:**与当前写入的位置前面的第 `k` 个元素进行比较,不相同则保留** -举个🌰,我们令 `k=2`,假设有如下样例 - -[1,1,1,1,1,1,2,2,2,2,2,2,3] +举个🌰,我们令 `k=2`,假设有如下样例 $[1,1,1,1,1,1,2,2,2,2,2,2,3]$ 1. 首先我们先让前 2 位直接保留,得到 1,1 2. 对后面的每一位进行继续遍历,能够保留的前提是与当前位置的前面 `k` 个元素不同(答案中的第一个 1),因此我们会跳过剩余的 1,将第一个 2 追加,得到 1,1,2