From 09555d1c6da91cffbcdafff136abb58c53b8e35c Mon Sep 17 00:00:00 2001 From: lucifer Date: Wed, 23 Sep 2020 23:23:25 +0800 Subject: [PATCH] feat: binode-lcci --- .vscode/launch.json | 6 + collections/easy.md | 2 + problems/binode-lcci.md | 139 ++++++++++++++++++ .../215.kth-largest-element-in-an-array.js | 38 ++--- todo/candidates/64.minimum-path-sum.js | 5 +- todo/candidates/good-array.py | 36 +++++ 6 files changed, 205 insertions(+), 21 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 problems/binode-lcci.md create mode 100644 todo/candidates/good-array.py diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..a6ac4bba7 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,6 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0" +} diff --git a/collections/easy.md b/collections/easy.md index 074a4a8d7..c4833da00 100644 --- a/collections/easy.md +++ b/collections/easy.md @@ -1,3 +1,5 @@ +- [binode-lcci](../problems/binode-lcci.md) 🆕 + - [0001.two-sum](../problems/1.two-sum.md) - [0020.Valid Parentheses](../problems/20.valid-parentheses.md) - [0021.MergeTwoSortedLists](../problems/21.merge-two-sorted-lists.md) diff --git a/problems/binode-lcci.md b/problems/binode-lcci.md new file mode 100644 index 000000000..2793201fe --- /dev/null +++ b/problems/binode-lcci.md @@ -0,0 +1,139 @@ +# 题目地址(面试题 17.12. BiNode) + +https://leetcode-cn.com/problems/binode-lcci/ + +## 题目描述 + +``` +二叉树数据结构TreeNode可用来表示单向链表(其中left置空,right为下一个链表节点)。实现一个方法,把二叉搜索树转换为单向链表,要求依然符合二叉搜索树的性质,转换操作应是原址的,也就是在原始的二叉搜索树上直接修改。 + +返回转换后的单向链表的头节点。 + +注意:本题相对原题稍作改动 + +  + +示例: + +输入: [4,2,5,1,3,null,6,0] +输出: [0,null,1,null,2,null,3,null,4,null,5,null,6] +提示: + +节点数量不会超过 100000。 +``` + +## 前置知识 + +- 二叉查找树 +- 递归 +- [二叉树的遍历](../thinkings/binary-tree-traversal.md) + +## 公司 + +- 暂无 + +## 思路 + +实际上这就是一个考察二叉树遍历 + 二叉查找树性质的题目。需要注意的是指针操作,这一点和链表反转系列题目是一样的。 + +首先我们要知道一个性质: 对于一个二叉查找树来说,其中序遍历结果是一个有序数组。 而题目要求你输出的恰好就是有序数组(虽然没有明说, 不过从测试用例也可以看出)。 + +因此一个思路就是中序遍历, 边遍历边改变指针即可。 这里有两个注意点: + +1. 指针操作小心死循环 +2. 你需要返回的是最左下角的节点,而不是题目给的 root + +对于第一个问题, 其实只要注意操作指针的顺序即可。对于第二个问题,我用了一个黑科技,让代码看起来简洁又高效。如果不懂的话, 你也可以换个朴素的写法。 + +让我们进入正题。 + +其中绿色是我们要增加的连线,而黑色是是原本的连线。 + +![](https://tva1.sinaimg.cn/large/007S8ZIlly1gj0zk657mmj30qq0doabd.jpg) + +我们再来看一个复杂一点的: + +![](https://tva1.sinaimg.cn/large/007S8ZIlly1gj0zl95r69j31040m6tbc.jpg) + +实际上,不管多么复杂。 我们只需要进行一次**中序遍历**,同时记录前驱节点。然后操作修改前驱节点和当前节点的指针即可,整个过程就好像是链表反转。 + +核心代码(假设 pre 我们已经正确计算出了): + +```py +cur.left = None +pre.right = cur +pre = cur +``` + +剩下的就是如何计算 pre,这个也不难,直接看代码: + +```py +self.pre = None +def dfs(root): + dfs(root.left) + # 上面的指针改变逻辑写到这里 + self.pre = root + dfs(root.right) + +``` + +问题得以解决。 + +这里还有最后一个问题就是返回值,题目要返回的实际上是最左下角的值。而我用了一个黑科技的方法(注意看注释): + +```py +self.pre = self.ans = TreeNode(-1) +def dfs(root): + if not root: return + dfs(root.left) + root.left = None + self.pre.right = root + # 当第一次执行到下面这一行代码,恰好是在最左下角, 这个时候 self.pre = root 就切断了 self.pre 和 self.ans 的联系 + # 之后 self.pre 的变化都不会体现到 self.ans 上。 + # 直观上来说就是 self.ans 在遍历到最左下角的时候下车了 + # 因此最后返回 self.ans 即可 + self.pre = root + dfs(root.right) +dfs(root) +return self.ans.right +``` + +## 关键点 + +- 指针操作 +- 返回值的处理 + +## 代码 + +```py +class Solution: + def convertBiNode(self, root): + self.pre = self.ans = TreeNode(-1) + def dfs(root): + if not root: return + dfs(root.left) + root.left = None + self.pre.right = root + self.pre = root + dfs(root.right) + dfs(root) + return self.ans.right + +``` + +**复杂度分析** + +- 时间复杂度:$O(N)$,其中 N 为树的节点总数。 +- 空间复杂度:$O(h)$,其中 h 为树的高度。 + +## 相关题目 + +- [206.reverse-linked-list](./206.reverse-linked-list.md) +- [92.reverse-linked-list-ii](./92.reverse-linked-list-ii.md) +- [25.reverse-nodes-in-k-groups-cn](./25.reverse-nodes-in-k-groups-cn.md) + +## 扩展 + +大家也可以关注我的公众号《脑洞前端》获取更多更新鲜的 LeetCode 题解 + +![](https://tva1.sinaimg.cn/large/007S8ZIlly1ghluc9tkv6j30x20iwjtf.jpg) diff --git a/todo/candidates/215.kth-largest-element-in-an-array.js b/todo/candidates/215.kth-largest-element-in-an-array.js index 358a152aa..4ab699a21 100644 --- a/todo/candidates/215.kth-largest-element-in-an-array.js +++ b/todo/candidates/215.kth-largest-element-in-an-array.js @@ -9,26 +9,28 @@ * @return {number} */ function maxHeapify(nums) { - nums.unshift(null); - - for (let i = nums.length - 1; i >> 1 > 0; i--) { - // 自下往上堆化 - if (nums[i] > nums[i >> 1]) { // 如果子元素更大,则交换位置 - const temp = nums[i]; - nums[i] = nums[i >> 1]; - nums[i >> 1] = temp; - } + nums.unshift(null); + + for (let i = nums.length - 1; i >> 1 > 0; i--) { + // 自下往上堆化 + if (nums[i] > nums[i >> 1]) { + // 如果子元素更大,则交换位置 + const temp = nums[i]; + nums[i] = nums[i >> 1]; + nums[i >> 1] = temp; } + } + nums.shift(); + return nums[0]; +} +var findKthLargest = function (nums, k) { + // heap klogn + let ret = null; + for (let i = 0; i < k; i++) { + ret = maxHeapify(nums); nums.shift(); - return nums[0]; } -var findKthLargest = function(nums, k) { - // heap klogn - let ret = null; - for(let i = 0; i < k; i++) { - ret = maxHeapify(nums); - nums.shift(); - } - return ret; + return ret; }; +findKthLargest([1, 2, 3, 4, 5], 2); diff --git a/todo/candidates/64.minimum-path-sum.js b/todo/candidates/64.minimum-path-sum.js index 722ea8a02..d113aa32b 100644 --- a/todo/candidates/64.minimum-path-sum.js +++ b/todo/candidates/64.minimum-path-sum.js @@ -7,8 +7,8 @@ * @param {number[][]} grid * @return {number} */ -var minPathSum = function(grid) { -// 时间复杂度和空间复杂度都是 O (m * n); +var minPathSum = function (grid) { + // 时间复杂度和空间复杂度都是 O (m * n); if (grid.length === 0) return 0; const dp = []; const rows = grid.length; @@ -39,4 +39,3 @@ var minPathSum = function(grid) { return dp[rows][cols]; }; - diff --git a/todo/candidates/good-array.py b/todo/candidates/good-array.py new file mode 100644 index 000000000..339eb5bae --- /dev/null +++ b/todo/candidates/good-array.py @@ -0,0 +1,36 @@ +# Install the python extension for VS Code +# (https:#marketplace.visualstudio.com/items?itemName=ms-python.python). + +# The Debug Visualizer has no support for Python data extractors yet, +# so to visualize data, your value must be a valid JSON string representing the data. +# See readme for supported data schemas. + +from json import dumps +from random import randint + +graph = { + "kind": {"graph": True}, + "nodes": [ + {"id": "1", "label": "1"} + ], + "edges": [] +} + +for i in range(2, 100): + # add a node + id = str(i) + graph["nodes"].append({"id": id, "label": id}) + # connects the node to a random edge + targetId = str(randint(1, i - 1)) + graph["edges"].append({"from": id, "to": targetId}) + json_graph = dumps(graph) + print("i is " + str(i)) + # try setting a breakpoint right above + # then put json_graph into the visualization console and press enter + # when you step through the code each time you hit the breakpoint + # the graph should automatically refresh! + +# example of json_graph visualization with 10 nodes: +# https://i.imgur.com/RqZuYHH.png + +print("finished")