<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Yosgi Blog</title><link>https://siqi-liu.com/en/post/</link><description>Recent content in Posts on Yosgi Blog</description><generator>Hugo</generator><language>en</language><lastBuildDate>Fri, 12 Jun 2026 04:28:41 +0000</lastBuildDate><atom:link href="https://siqi-liu.com/en/post/index.xml" rel="self" type="application/rss+xml"/><item><title>From Extracting Drawing Text to Placing 2D Annotations in a 3D Scene</title><link>https://siqi-liu.com/en/post/from-extracting-drawing-text-to-placing-2d-annotations-in-a-3d-scene/</link><pubDate>Thu, 11 Jun 2026 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/from-extracting-drawing-text-to-placing-2d-annotations-in-a-3d-scene/</guid><description>A practical engineering recap of how a simple drawing text extraction task turned into a 2D-to-3D mapping workflow for digital twins, combining SVG parsing, vision models, geometry rules, registration math, and agent tool design.</description></item><item><title>AI Won’t Replace Software Engineers. It Will Replace the Parts of Coding We Never Loved.</title><link>https://siqi-liu.com/en/post/ai-won-t-replace-software-engineers-it-will-replace-the-parts-of-coding-we-never-loved/</link><pubDate>Tue, 19 May 2026 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/ai-won-t-replace-software-engineers-it-will-replace-the-parts-of-coding-we-never-loved/</guid><description>AI will not replace software engineers as a whole. It will remove much of the repetitive, mechanical work and give engineers more leverage to focus on judgment, systems, users, and building better products.</description></item><item><title>Your Agent Is Not Inconsistent Because It Is Dumb. It Just Has Too Many Tool Paths.</title><link>https://siqi-liu.com/en/post/your-agent-is-not-inconsistent-because-it-is-dumb-it-just-has-too-many-tool-paths/</link><pubDate>Thu, 07 May 2026 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/your-agent-is-not-inconsistent-because-it-is-dumb-it-just-has-too-many-tool-paths/</guid><description>Multi-tool agents become unreliable when the same task takes different tool paths each time. This article explains why Skills should preserve validated execution paths, not one-off results, and why those Skills need to evolve over time.</description></item><item><title>Tool for Control, Code for Analysis(3)</title><link>https://siqi-liu.com/en/post/tool-for-control-code-for-analysis3/</link><pubDate>Wed, 28 Jan 2026 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/tool-for-control-code-for-analysis3/</guid><description>In large-scale Agent systems, pure Tool-based approaches tend to collapse under context pressure, while pure Code-based approaches introduce excessive latency. Based on real-world experiments, this article introduces a dual-path execution model that uses a “Context Off-Ramp” to switch between Tool and Code execution.</description></item><item><title>Why Tool and Code Fail Differently in Agent Systems（2）</title><link>https://siqi-liu.com/en/post/why-tool-and-code-fail-differently-in-agent-systems2/</link><pubDate>Sat, 27 Dec 2025 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/why-tool-and-code-fail-differently-in-agent-systems2/</guid><description>Tool and Code do not just differ in expressiveness; they also fail at different times. This article explains why multi-round Agent systems amplify that difference.</description></item><item><title>An MCP-as-Code Refactor, and Why It Did Not Work the Way I Expected</title><link>https://siqi-liu.com/en/post/an-mcp-as-code-refactor-and-why-it-did-not-work-the-way-i-expected1/</link><pubDate>Thu, 18 Dec 2025 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/an-mcp-as-code-refactor-and-why-it-did-not-work-the-way-i-expected1/</guid><description>A real-world MCP-as-Code refactor on where Code helps, where Tool still fits better, and why Agent runtime needs both.</description></item><item><title>2025 Investment Review</title><link>https://siqi-liu.com/en/post/2025-investment-review/</link><pubDate>Mon, 15 Dec 2025 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/2025-investment-review/</guid><description>2025 Investment Review: A Bet-the-Dip Strategy in AI-Driven Markets</description></item><item><title>High-Frequency Synchronization Architecture Between React State and a 3D Engine</title><link>https://siqi-liu.com/en/post/high-frequency-synchronization-architecture-between-react-state-and-a-3d-engine/</link><pubDate>Wed, 01 Oct 2025 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/high-frequency-synchronization-architecture-between-react-state-and-a-3d-engine/</guid><description>A synchronization paradigm for massive real-time data: a middle layer isolates high-frequency data sources, and React consumes only the linear projection of the visible viewport.</description></item><item><title>Early Experiences with Building MCP Tools</title><link>https://siqi-liu.com/en/post/early-experiences-with-building-mcp-tools/</link><pubDate>Tue, 01 Jul 2025 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/early-experiences-with-building-mcp-tools/</guid><description>How Cut 6,000 Tokens Down to 500</description></item><item><title>Circle After the Hype, Was a $40 Billion Valuation Justified?</title><link>https://siqi-liu.com/en/post/circle-after-the-hype-was-a-40-billion-valuation-justified/</link><pubDate>Sun, 29 Jun 2025 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/circle-after-the-hype-was-a-40-billion-valuation-justified/</guid><description>Circle is a high-quality company operating in a promising sector, but at a valuation of roughly $40 billion, the market had already priced in a substantial portion of its future growth.</description></item><item><title>1104-Binary Tree Pathfinding</title><link>https://siqi-liu.com/en/post/1104-binary-tree-pathfinding/</link><pubDate>Thu, 29 Jul 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/1104-binary-tree-pathfinding/</guid><description>The first thing I thought of was to construct a binary tree, and then use the symmetric relationship of each layer to find the parent node var pathInZigZagTree = function(label) { let stack = [] for (let i = 1; i &lt;= label; i++) { let level = Math.floor(Math.log(i) / Math.log(2)) if (!stack[level]) { stack[level] = [] } if (level % 2 === 0) { stack[level].push(i) } else { stack[level].unshift(i) } } var level = Math.floor(Math.log(label) / Math.log(2)) let ans = [] while (level) { ans.push(label) level-- label = Math.floor(label / 2) let index = stack[level].length - 1 - stack[level].indexOf(label) label = stack[level][index] } ans.push(1) return ans.reverse() }Sorry, timeout. Inspired by the answer, since it is symmetrical, the sum of the symmetrical numbers is the same when the number of layers is the same.</description></item><item><title>Reverse Linked List 2</title><link>https://siqi-liu.com/en/post/reverse-linked-list-2/</link><pubDate>Fri, 23 Jul 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/reverse-linked-list-2/</guid><description>Considering that the head may also be reversed, a dummy head is needed. During the traversal process, the tail node after the reversal and the previous node are recorded. Finally, the node link processing is performed. var reverseBetween = function(head, m, n) { let noob = new ListNode(0) noob.next = head let cur = noob let index = 0 let A,B while (index &lt; m) { A = cur // A records the previous node of the reverse subchain cur = cur.next index++ } B = cur // B records the tail node after reversal let pre = cur while (index &lt;= n) { let next = cur.next cur.next = pre pre = cur cur = next index++ } // After execution, the cur pointer is at the next node of the reverse subchain B.next = cur A.next = pre return noob.next };</description></item><item><title>1893-Check if all integers in the region are covered</title><link>https://siqi-liu.com/en/post/1893-check-if-all-integers-in-the-region-are-covered/</link><pubDate>Fri, 23 Jul 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/1893-check-if-all-integers-in-the-region-are-covered/</guid><description>I didn’t think of any good way to get it, so I used brute force to solve it first. var isCovered = function(ranges, left, right) { for(let i = left ; i &lt;= right ; i ++) { let include = false for(let index = 0 ; index &lt; ranges.length ; index ++) { let [start,end] = ranges[index] if (i &gt;=start &amp;&amp; i &lt;=end) { include = true } } if (!include) return false } return true};Thinking about optimization, you can use start, end. When start &lt;= left, the [left … end] set is already included. Continue compressing [end + 1, right] until there are no elements in the set. var isCovered = function(ranges, left, right) { ranges = ranges.sort((a,b) =&gt; a - b) for(let i = 0 ; i &lt; ranges.length;i++) { let [start,end] = ranges[i]; // Shrink the left boundary according to the range if (start &lt;= left) { left = Math.max(end,right) } if (left &gt;= right) { return true } } return left &gt;= right };I didn’t think of any good way to get it, so I used brute force to solve it first.</description></item><item><title>138-Copying a linked list with random pointers</title><link>https://siqi-liu.com/en/post/138-copying-a-linked-list-with-random-pointers/</link><pubDate>Thu, 22 Jul 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/138-copying-a-linked-list-with-random-pointers/</guid><description>The idea behind the question is to use double pointers to point to the old and new nodes, and then add a map to map the old and new nodes. recursion var listMap = new Map() var copyRandomList = function(head) { if(head === null) return head if (listMap.get(head)) { return listMap.get(head) } let newNode = new Node(head.val,null,null) listMap.set(head, newNode) newNode.next = copyRandomList(head.next) newNode.random = copyRandomList(head.random) return newNode }; ```Iteration ```javascript var copyRandomList = function(head) { if(head == null) return head var listMap = new Map() listMap.set(null,null) var cur = head while (cur!= null) { listMap.set(cur,new Node(cur.val,null,null)) cur = cur.next } cur = head while (cur!= null) { listMap.get(cur).next = listMap.get(cur.next) listMap.get(cur).random = listMap.get(cur.random) cur = cur.next } return listMap.get(head) };The idea behind the question is to use double pointers to point to the old and new nodes, and then add a map to map the old and new nodes.</description></item><item><title>684-Redundant Connection</title><link>https://siqi-liu.com/en/post/684-redundant-connection/</link><pubDate>Wed, 07 Jul 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/684-redundant-connection/</guid><description>Time: 15 minutes Use the union-find template var findRedundantConnection = function(edges) { var n = edges.length var fa = new Array(n + 1) var find = function (x) { if (x != fa[x]) { fa[x] = find(fa[x]) } return fa[x] } for(let i = 1 ; i &lt;= n ; i ++) { fa[i] = i } for(let i = 0 ; i &lt; n ; i ++) { var [x,y] = edges[i] if (find(x) === find(y)) { return [x,y] } else { fa[find(x)] = find(y) } } };</description></item><item><title>1202-Swap elements in a string</title><link>https://siqi-liu.com/en/post/1202-swap-elements-in-a-string/</link><pubDate>Tue, 06 Jul 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/1202-swap-elements-in-a-string/</guid><description>It is mainly used for learning and checking ideas, and you will start only after looking at the answers. The idea is to group the interchangeable strings first, sort the groups, and then combine them Union-find is to use recursion or while loop to implement find, and then use arrays and subscripts to implement union var smallestStringWithSwaps = function(s, pairs) { var fa = [] var find = function (x) { if (x === fa[x]) { return x } else { return fa[x] = find(fa[x]) } } for (let i = 0; i &lt; s.length; i++) { fa[i] = i } for(let i = 0 ; i &lt; pairs.length ; i ++) { const [x,y] = pairs[i] fa[find(x)] = find(y) } var n = s.length // Calculate the grouped map const vec = new Array(n).fill(0).map(() =&gt; new Array()); for (let i = 0; i &lt; n; i++) { fa[i] = find(i); vec[fa[i]].push(s[i]); } console.log(fa) // Sort the grouped map for (let i = 0; i &lt; n; ++i) { if (vec[i].length &gt; 0) { vec[i].sort((a, b) =&gt; a.charCodeAt() - b.charCodeAt()); } } // Combined into ans const ans = new Array(n).fill(0); for (let i = 0; i &lt; n; ++i) { var group = fa[i] if ( group!= undefined &amp;&amp; vec[group].length) { // Take out the smallest number in each group ans[i] = vec[fa[i]].shift() } else { ans[i] = s[i] } } return ans.join('') };It is mainly used to learn and check the ideas, and you will start only after looking at the answers.</description></item><item><title>778-Swimming in a rising pool</title><link>https://siqi-liu.com/en/post/778-swimming-in-a-rising-pool/</link><pubDate>Mon, 05 Jul 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/778-swimming-in-a-rising-pool/</guid><description>Time: 20 minutes First of all, it can be seen that this is a question to examine DFS var swimInWater = function(grid) { let row = grid.length; let col = grid[0].length; var step = 0 while(true) { for(let i = 0 ; i &lt; row ; i ++) { for(let j = 0 ; j &lt; col ; j ++){ grid[i][j] -- } } var visited = [] for(let i = 0 ; i &lt; row ; i ++) { let arr = [] for(let j = 0 ; j &lt; col ; j ++) { arr.push(false) } visited.push(arr) } var dfs = function (i,j) { if ( i&lt; 0 || j &lt; 0 || i &gt;= row || j &gt;= col) return false if (visited[i][j]) { return false } else { visited[i][j] = true } if (grid[i][j] &gt; 0) return false if (i === row - 1 &amp;&amp; j === col - 1 &amp;&amp; grid[i][j] &lt;= 0) return true return dfs(i+1,j) || dfs(i-1,j) || dfs(i,j-1)|| dfs(i,j + 1) } step++ if (dfs(0,0) === true) break } return step };We don’t have to start from 1, we can use the binary search to find the leftmost insertion point. var swimInWater = function(grid) { let row = grid.length; let col = grid[0].length; let right = -Infinity let left = Infinity for(let i = 0 ; i &lt; row ; i ++) { for(let j = 0 ; j &lt; col ; j ++ ){ let num = grid[i][j] right = Math.max(right,num) left = Math.min(left,num) } } let mid = left + Math.floor( (right - left) / 2 ) while(left &lt;= right) { mid = left + Math.floor( (right - left) / 2 ) var visited = [] var new_grid = [] for(let i = 0 ; i &lt; row ; i ++) { let arr = [] let _grid = [] for(let j = 0 ; j &lt; col ; j ++) { arr.push(false) _grid.push(grid[i][j] - mid) } visited.push(arr) new_grid.push(_grid) } var dfs = function (i,j) { if ( i &lt; 0 || j &lt; 0 || i &gt;= row || j &gt;= col) return false if (visited[i][j]) { return false } else { visited[i][j] = true } if (new_grid[i][j] &gt; 0) return false if (i === row - 1 &amp;&amp; j === col - 1 &amp;&amp; new_grid[i][j] &lt;= 0) return true return dfs(i+1,j) || dfs(i-1,j) || dfs(i,j-1)|| dfs(i,j + 1) } if(dfs(0,0)) { // Found the spare tire, continue to see if it can be smaller right = mid - 1 } else { left = mid + 1 } } return left };</description></item><item><title>475-Heater</title><link>https://siqi-liu.com/en/post/475-heater/</link><pubDate>Thu, 10 Jun 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/475-heater/</guid><description>The first thing that comes to mind is to find the distance r of all heaters that are the shortest distance from the house, and then return the largest r var findRadius = function(houses, heaters) { var max = 0 for(let i = 0 ; i &lt; houses.length ; i ++) { var house_position = houses[i] var r = Infinity for(let j = 0 ; j &lt; heaters.length ; j ++) { var heat_position = heaters[j] var reduce = Math.abs(house_position - heat_position) r = Math.min(r,reduce) } max = Math.max(r,max) } return max };In this case, we can also use the dichotomy method to find the heater var findRadius = function(houses, heaters) { var r = 0 for(let i = 0 ; i &lt; houses.length ; i ++) { var house_position = houses[i] let left = 0 , right = heaters.length - 1 // Find the heat_position closest to house_position // That is, find the rightmost insertion point of house_position while(left &lt;= right &amp;&amp; right &lt; heaters.length) { let mid = left + Math.floor((right - left) / 2) var heat_position = heaters[mid] // If the one found is not greater than, go to the right if(heat_position &lt;= house_position) { left = mid + 1 } else { right = mid - 1 } } // The insertion point found at this time is not necessarily the closest one. The one on the left is smaller than it, so we need to compare it var R = Math.abs(heaters[right] - house_position) if(right &gt; 0) { R = Math.min( Math.abs( heaters[right - 1] - house_position) , R) } r = Math.max(r,R) } return r };</description></item><item><title>875-Keke who loves bananas</title><link>https://siqi-liu.com/en/post/875-keke-who-loves-bananas/</link><pubDate>Wed, 28 Apr 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/875-keke-who-loves-bananas/</guid><description>Time: 60 minutes The quickest way of thinking when getting the question is to enumerate all the speeds at which bananas can be eaten and find the minimum speed at which all bananas can be eaten. The enumeration speed range is [1… the largest pile of bananas], because the speed will not be less than 1, and there is no need for the speed to be faster than the largest pile of bananas.</description></item><item><title>973-K points closest to the origin</title><link>https://siqi-liu.com/en/post/973-k-points-closest-to-the-origin/</link><pubDate>Sat, 10 Apr 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/973-k-points-closest-to-the-origin/</guid><description>Time: 15 minutes There is nothing much to say about conventional heap sort class Heap { constructor(list, compare = (a, b) =&gt; a - b) { this.left = index =&gt; 2 * index + 1 this.right = index =&gt; 2 * index + 2 this.parent = index =&gt; Math.floor((index - 1) / 2) this.heapify = (index = 0) =&gt; { const { list } = this const leftIndex = this.left(index) const rightIndex = this.right(index) let maxIndex = index if (list[leftIndex] !== undefined &amp;&amp; this.compare(list[maxIndex], list[leftIndex]) &gt; 0) { maxIndex = leftIndex } if (list[rightIndex] !== undefined &amp;&amp; this.compare(list[maxIndex], list[rightIndex]) &gt; 0) { maxIndex = rightIndex } if (index !== maxIndex) { const temp = list[index] list[index] = list[maxIndex] list[maxIndex] = temp this.heapify(maxIndex) } } this.buildHeap = () =&gt; { for (let i = Math.floor(this.list.length / 2); i &gt;= 0; i--) { this.heapify(i) } return this.list } this.extract = () =&gt; { const temp = this.list[0] this.list[0] = this.list[this.list.length - 1] this.list[this.list.length - 1] = temp const result = this.list.pop() this.heapify(0) return result } this.top = () =&gt; { return this.list[0] } this.insert = (item) =&gt; { const { list } = this list.push(item) let index = list.length - 1 let parentIndex = this.parent(index) while (list[parentIndex] !== undefined &amp;&amp; this.compare(list[parentIndex], list[index]) &gt; 0) { const temp = list[index] list[index] = list[parentIndex] list[parentIndex] = temp index = parentIndex parentIndex = this.parent(index) } } this.list = list this.compare = compare this.buildHeap() } } var kClosest = function(points, k) { // To find the nearest point, a max heap should be used to store the k smallest var compare = function (a,b) { var A = a[0] * a[0] + a[1] * a[1] var B = b[1] * b[1] + b[0] * b[0] return B - A } var heap = new Heap([],(a,b) =&gt; { return compare(a,b) }) for(let i = 0 ; i &lt; points.length ; i ++) { if (i &lt; k) { heap.insert(points[i]) } else { var top = heap.top() // top is greater than the current value, exit top if(compare(points[i],top) &gt; 0) { heap.extract() heap.insert(points[i]) } } } return heap.list};</description></item><item><title>Interview Question-17-14-Minimum Number of K</title><link>https://siqi-liu.com/en/post/interview-question-17-14-minimum-number-of-k/</link><pubDate>Thu, 08 Apr 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/interview-question-17-14-minimum-number-of-k/</guid><description>Time: 10 minutes const swap = function (arr,i,j) { [arr[i],arr[j]] = [arr[j],arr[i]] } class MaxHeap { constructor() { this.count = 0 this.data = new Array(this.count + 1) } shiftUp(k) { // Put the new elements up while(k&gt;=1) { let father = Math.floor(k / 2) if (this.data[k] &gt; this.data[father]) { swap(this.data,k,father) k = father } else { break } } } shiftDown(k) { while( k * 2 &lt;= this.count) { // Indicates that k has children let j = k if (k * 2 + 1 &lt;= this.count &amp;&amp; this.data[k * 2 + 1] &gt; this.data[k] &amp;&amp; this.data[k * 2 + 1] &gt; this.data[k * 2]) { j = k * 2 + 1 } else if (this.data[k * 2] &gt; this.data[k]) { j = k * 2 } else { break } swap(this.data,j,k) k = j } } size() { return this.count } isEmpty() { return this.count === 0 } insert(item) { this.data[++this.count] = item this.shiftUp(this.count) } extractMax() { if (this.count &lt; 0) return let ret = this.data[1] swap(this.data,1,this.count--) this.shiftDown(1) return ret } top() { return this.data[1] } } var smallestK = function(arr, k) { var heap = new MaxHeap() var K = 0 while(K &lt; k) { heap.insert(arr[K]) K++ } // Maintain the heap at size K while(K &lt; arr.length) { var max = heap.top() if (arr[K] &lt; max) { heap.extractMax() heap.insert(arr[K]) } K++ } var size = heap.size() return heap.data.slice(1, 1 + size ) };</description></item><item><title>347-first-K-high-frequency elements</title><link>https://siqi-liu.com/en/post/347-first-k-high-frequency-elements/</link><pubDate>Thu, 08 Apr 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/347-first-k-high-frequency-elements/</guid><description>Time: 30 minutes The idea is to first use the time complexity of On to count, and then solve it using the minimum heap method class Heap { constructor(list, compare = (a, b) =&gt; a - b) { this.left = index =&gt; 2 * index + 1 this.right = index =&gt; 2 * index + 2 this.parent = index =&gt; Math.floor((index - 1) / 2) this.heapify = (index = 0) =&gt; { const { list } = this const leftIndex = this.left(index) const rightIndex = this.right(index) let maxIndex = index if (list[leftIndex] !== undefined &amp;&amp; this.compare(list[maxIndex], list[leftIndex]) &gt; 0) { maxIndex = leftIndex } if (list[rightIndex] !== undefined &amp;&amp; this.compare(list[maxIndex], list[rightIndex]) &gt; 0) { maxIndex = rightIndex } if (index !== maxIndex) { const temp = list[index] list[index] = list[maxIndex] list[maxIndex] = temp this.heapify(maxIndex) } } this.buildHeap = () =&gt; { for (let i = Math.floor(this.list.length / 2); i &gt;= 0; i--) { this.heapify(i) } return this.list } this.extract = () =&gt; { const temp = this.list[0] this.list[0] = this.list[this.list.length - 1] this.list[this.list.length - 1] = temp const result = this.list.pop() this.heapify(0) return result } this.top = () =&gt; { return this.list[0] } this.insert = (item) =&gt; { const { list } = this list.push(item) let index = list.length - 1 let parentIndex = this.parent(index) while (list[parentIndex] !== undefined &amp;&amp; this.compare(list[parentIndex], list[index]) &gt; 0) { const temp = list[index] list[index] = list[parentIndex] list[parentIndex] = temp index = parentIndex parentIndex = this.parent(index) } } this.list = list this.compare = compare this.buildHeap() } } var topKFrequent = function(nums, k) { var map = {} for(let i = 0 ; i &lt; nums.length ; i ++) { var num = nums[i] if (map[num] == undefined) { map[num] = 1 } else { map[num] ++ } } // Use a minimum heap to maintain the K highest elements var heap = new Heap([],(a,b) =&gt; a[1] - b[1]) var K = 0 // Because the api is a maximum heap, we need to take the opposite number Object.entries(map).forEach(([key,val]) =&gt; { if (K &lt; k) { heap.insert([key,-val]) } else { var top = heap.top() if (val &gt; - top[1]) { heap.extract() heap.insert([key,-val]) } } }) return heap.list.map((v) =&gt; v[0]).slice(0,k) };</description></item><item><title>295-Median of data streams</title><link>https://siqi-liu.com/en/post/295-median-of-data-streams/</link><pubDate>Wed, 24 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/295-median-of-data-streams/</guid><description>Time: Read the answer Since it is a pile exercise, it must be closer to the idea of pile Since we only want the median, there is no need to sort all the numbers. You can use two heaps, a maximum heap and a minimum heap When the total number is odd (i.e., the number of maximum heaps - minimum heaps = 1), get the maximum value of the maximum heap</description></item><item><title>1738-Find the K-th largest XOR coordinate value</title><link>https://siqi-liu.com/en/post/1738-find-the-k-th-largest-xor-coordinate-value/</link><pubDate>Mon, 22 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/1738-find-the-k-th-largest-xor-coordinate-value/</guid><description>Time: Refer to the answer After reading the title, the first thing that comes to mind is that dp cannot escape But writing the conversion equation requires some skill Observe that dp[1][1] = matrix[0][0] ^ matrix[0][1] ^ matrix[1][0] ^ matrix[1][1] Then use the property of XOR The same value is XORed to 0, and any value XORed with 0 is itself Can be written as dp[1][1] = matrix[0][0] ^ (matrix[0][1] ^ matrix[0][0]) ^ (matrix[1][0] ^ matrix[1][0]) ^ matrix[1][1]</description></item><item><title>865 - Minimum subtree with all deepest nodes</title><link>https://siqi-liu.com/en/post/865-minimum-subtree-with-all-deepest-nodes/</link><pubDate>Sun, 21 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/865-minimum-subtree-with-all-deepest-nodes/</guid><description>Time: 60 minutes I was misled by the depth of the question and thought that the calculation depth should be done from top to bottom. In fact, it can be done from bottom to top. If the left and right subtrees have the same height, return the node itself and its depth. If the left subtree is deeper, it means that the smallest and deepest part is in the left subtree. Return the left subtree and its own depth.</description></item><item><title>1046-The Weight of the Last Stone</title><link>https://siqi-liu.com/en/post/1046-the-weight-of-the-last-stone/</link><pubDate>Sun, 21 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/1046-the-weight-of-the-last-stone/</guid><description>Time: 10 minutes A simple question shouldn’t ask me to write the maximum heap by hand. const swap = function (arr,i,j) { [arr[i],arr[j]] = [arr[j],arr[i]] } class MaxHeap { constructor() { this.count = 0 this.data = new Array(this.count + 1) } shiftUp(k) { // Put the new elements up while(k&gt;=1) { let father = Math.floor(k / 2) if (this.data[k] &gt; this.data[father]) { swap(this.data,k,father) k = father } else { break } } } shiftDown(k) { while( k * 2 &lt;= this.count) { // Indicates that k has children let j = k if (k * 2 + 1 &lt;= this.count &amp;&amp; this.data[k * 2 + 1] &gt; this.data[k] &amp;&amp; this.data[k * 2 + 1] &gt; this.data[k * 2]) { j = k * 2 + 1 } else if (this.data[k * 2] &gt; this.data[k]) { j = k * 2 } else { break } swap(this.data,j,k) k = j } } size() { return this.count } isEmpty() { return this.count === 0 } insert(item) { this.data[++this.count] = item this.shiftUp(this.count) } extractMax() { if (this.count &lt; 0) return let ret = this.data[1] swap(this.data,1,this.count--) this.shiftDown(1) return ret } } var lastStoneWeight = function(stones) { var heap = new MaxHeap() for(let i = 0 ; i &lt; stones.length ; i++) { heap.insert(stones[i]) } while(heap.size() &gt; 1) { var s1 = heap.extractMax() var s2 = heap.extractMax() var reduce = Math.abs(s1 - s2) if (reduce) { heap.insert(reduce) } } if (heap.size() === 0) { return 0 } return heap.extractMax() };Time: 10 minutes</description></item><item><title>783-Binary Search Tree Node Minimum Distance</title><link>https://siqi-liu.com/en/post/783-binary-search-tree-node-minimum-distance/</link><pubDate>Thu, 18 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/783-binary-search-tree-node-minimum-distance/</guid><description>Time: 10 minutes Solve by using the property of pre-order traversal of binary tree var minDiffInBST = function(root) { var min = Infinity var pre = null var dfs = function (root) { if (!root) return if (root.left) { dfs(root.left) } if (pre == null) { pre = root.val } else { console.log(pre,root.val) var reduce = Math.abs(pre - root.val) min = Math.min(min,reduce) pre = root.val } if (root.right) { dfs(root.right) } } dfs(root) return min };</description></item><item><title>814-Binary Tree Pruning</title><link>https://siqi-liu.com/en/post/814-binary-tree-pruning/</link><pubDate>Wed, 17 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/814-binary-tree-pruning/</guid><description>Time: 6 minutes It’s very simple. In-order traversal, calculate whether the value 1 exists in the subtrees on both sides, and remove it if not. If the left or right subtree or the tree itself contains 1, return true. Otherwise, return false. var pruneTree = function(root) { var DFS = function (root) { if (!root) return false var left = DFS(root.left) var right = DFS(root.right) if (!left) { root.left = null } if (!right) { root.right = null } if (left) { return true } if (right) { return true } if( root.val === 1) { return true } } var dummp = new TreeNode(1) dummp.left = root DFS(dummp) return dummp.left};One point to note is that the root itself may also need to be pruned, so a virtual node is added as the parent node</description></item><item><title>1448-Count the number of good nodes in a binary tree</title><link>https://siqi-liu.com/en/post/1448-count-the-number-of-good-nodes-in-a-binary-tree/</link><pubDate>Wed, 17 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/1448-count-the-number-of-good-nodes-in-a-binary-tree/</guid><description>Notes on counting good nodes in a binary tree using DFS with a running max.</description></item><item><title>1325-Delete the leaf node of the given value</title><link>https://siqi-liu.com/en/post/1325-delete-the-leaf-node-of-the-given-value/</link><pubDate>Wed, 17 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/1325-delete-the-leaf-node-of-the-given-value/</guid><description>Post-order traversal approach to delete target-valued leaf nodes using a dummy root.</description></item><item><title>1022 - the sum of the binary numbers from root to leaf</title><link>https://siqi-liu.com/en/post/1022-the-sum-of-the-binary-numbers-from-root-to-leaf/</link><pubDate>Wed, 17 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/1022-the-sum-of-the-binary-numbers-from-root-to-leaf/</guid><description>Time: 10 minutes The preorder is calculated from top to bottom, there is nothing much to say Converting binary to decimal is quite difficult, so I just parseInt(path, 2) var sumRootToLeaf = function(root) { var ans = 0 var dfs = function (root,path) { if (!root) return path += root.val if (!root.left &amp;&amp; !root.right) { ans += parseInt(path, 2) } root.left &amp;&amp; dfs(root.left,path) root.right &amp;&amp; dfs(root.right,path) } dfs(root,'') return ans };Time: 10 minutes The preorder is calculated from top to bottom, there is nothing much to say Converting binary to decimal is quite difficult, so I just parseInt(path, 2) var sumRootToLeaf = function(root) { var ans = 0 var dfs = function (root,path) { if (!root) return path += root.val if (!root.left &amp;&amp; !root.right) { ans += parseInt(path, 2) } root.left &amp;&amp; dfs(root.left,path) root.right &amp;&amp; dfs(root.right,path) } dfs(root,'') return ans };</description></item><item><title>Interview Question-04-12-Sum Path</title><link>https://siqi-liu.com/en/post/interview-question-04-12-sum-path/</link><pubDate>Tue, 16 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/interview-question-04-12-sum-path/</guid><description>Time: 20 minutes Because we are looking for “the path starting from each node is sum” Obviously, backtracking comes to mind. Since it is a binary tree, double recursion is used. The outer recursion is used to find all nodes, and the inner recursion is used to calculate the path of the nodes. var pathSum = function(root, sum) { var res = 0 var dfs = function (root,total,visited) { if (!root) return if (total + root.val == sum) { res++ } else if (total + root.val &gt; sum) { return } dfs(root.left,total + root.val,[...visited,root.val]) dfs(root.right,total + root.val,[...visited,root.val]) } var dfs_outer = function (root) { if (!root )return root.left &amp;&amp; dfs_outer(root.left) dfs(root,0,[]) root.right &amp;&amp; dfs_outer(root.right) } dfs_outer(root) return res };</description></item><item><title>563-Slope of Binary Tree</title><link>https://siqi-liu.com/en/post/563-slope-of-binary-tree/</link><pubDate>Tue, 16 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/563-slope-of-binary-tree/</guid><description>Time: 15 minutes Time: 15 minutes My first reaction when I got the question was to use recursion, but after I started writing it, I found that The condition that recursion needs to meet is that the problem can be split into sub-problems, but according to the meaning of the question, what we need to find is the difference between the sum of the left and right nodes of each node. This “sum of the left and right nodes” is a different problem for each node.</description></item><item><title>129-Find the sum of numbers from the root node to the leaf node</title><link>https://siqi-liu.com/en/post/129-find-the-sum-of-numbers-from-the-root-node-to-the-leaf-node/</link><pubDate>Tue, 16 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/129-find-the-sum-of-numbers-from-the-root-node-to-the-leaf-node/</guid><description>The question is about starting from the root node. The first thing that comes to mind is top-down DFS, passing parameters downward, and the end condition has no left or right children. Start with the pre-order traversal, and you can assume that all the previous nodes have been processed. var sumNumbers = function(root) { var ans = 0 var DFS = function (root,path) { if (!root) return path += root.val if (!root.left &amp;&amp; !root.right) { ans += Number(path) } root.left &amp;&amp; DFS(root.left,path) DFS(root.right, path) } DFS(root,'') return ans };The question is about starting from the root node. The first thing that comes to mind is top-down DFS, passing parameters downward, and the end condition has no left or right children.</description></item><item><title>124-Maximum Path Sum in a Binary Tree</title><link>https://siqi-liu.com/en/post/124-maximum-path-sum-in-a-binary-tree/</link><pubDate>Mon, 15 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/124-maximum-path-sum-in-a-binary-tree/</guid><description>Time: 30 minutes Once you understand the question, you can actually do it quickly. The question is about the value of any node. We can find the value of each node and choose the largest one. Since the path cannot return, we know that the path of the child node of the root node we start from can only choose left or right, or neither, and the result is x When finding max, compare x with the case where both sides are selected.</description></item><item><title>99-Restore Binary Search Tree</title><link>https://siqi-liu.com/en/post/99-restore-binary-search-tree/</link><pubDate>Sat, 13 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/99-restore-binary-search-tree/</guid><description>Time: 60 minutes The idea is still in-order traversal, using pre to cache the previous node. Because the in-order traversal is incremental, you must find the larger one first and then the smaller one. So the first problem is pre, the second is root var recoverTree = function(root) { var left = null var right = null var pre = null // You must find the big one first, then the small one, so the first one to have a problem is pre, and the second one to have a problem is root var DFS = function (root) { if (root.left) { DFS(root.left) } if (pre) { console.log(pre.val) if (pre.val &gt; root.val) { if(!left) { left = pre right = root } else { right = root } } pre = root } else { pre = root } if (root.right) { DFS(root.right) } } DFS(root) if (left &amp;&amp; right) { [left.val,right.val] = [right.val,left.val] } return root}</description></item><item><title>98-Verify Binary Search Tree</title><link>https://siqi-liu.com/en/post/98-verify-binary-search-tree/</link><pubDate>Sat, 13 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/98-verify-binary-search-tree/</guid><description>Time: 10 minutes Just use the increasing property of in-order traversal of the binary search tree In-order traversal to find the left child Does pre exist? If not, assign , find the right child, and return 1 If it exists, is it less than val? If yes, do not increment, and return false If not, increment, assign pre, and return 1 var isValidBST = function(root) { var preVal = null var DFS = function(root) { var left = true var right = true if (root.left) { left = DFS(root.left) } if (preVal !== null) { if (preVal &gt;= root.val) return false preVal = root.val } else { preVal = root.val } if (root.right) { right = DFS(root.right) } return left &amp;&amp; right } return DFS(root) };</description></item><item><title>863-All nodes with distance -K- in a binary tree</title><link>https://siqi-liu.com/en/post/863-all-nodes-with-distance-k-in-a-binary-tree/</link><pubDate>Sat, 13 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/863-all-nodes-with-distance-k-in-a-binary-tree/</guid><description>Time: 60 minutes The idea is still very simple. First use DFS to add a parent to each node, and find the required target by the way. Then starting from the target, use DFS to find a point K away from the target. Find all the parents of target in turn and use DFS to find the point with a distance K. The reason why it takes so much time is that after finding the parent, DFS is used to find it back, causing a memory overflow.</description></item><item><title>662-Binary Tree Maximum Width</title><link>https://siqi-liu.com/en/post/662-binary-tree-maximum-width/</link><pubDate>Sat, 13 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/662-binary-tree-maximum-width/</guid><description>Time: 120 minutes The initial idea was to use BFS, and remove a whole queue when removing it (later I learned that this is called breadth traversal) Then the double pointer finds the left and right nodes. End when both the left and right nodes do not exist var widthOfBinaryTree = function(root) { var que = [root] var max = 0 while(que.length) { var len = que.length var left = 0 var right = que.length - 1 while(!que[left] &amp;&amp; left &lt; len) { left ++ } while(!que[right] &amp;&amp; right &gt;= 0) { right -- } if (left &gt; right) { break } max = Math.max(max,right - left+ 1) for(let i = 0 ; i &lt; len ; i ++) { var node = que.shift() if (!node) { que.push(node) que.push(node) continue } node.left ? que.push(node.left) : que.push(null) node.right ? que.push(node.right) : que.push(null) } } return max };Soon, the submission showed that the execution exceeded the time limit, so a queue for storing sequence numbers was added, which was synchronized with the BFS stack to calculate the left and right distances.</description></item><item><title>222-Number of nodes in a complete binary tree</title><link>https://siqi-liu.com/en/post/222-number-of-nodes-in-a-complete-binary-tree/</link><pubDate>Sat, 13 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/222-number-of-nodes-in-a-complete-binary-tree/</guid><description>Time: 80 minutes The first reaction when I got the question was of course to solve it with DFS. But this is a complete binary tree, so we should use the properties of a complete binary tree. You can examine the depth of the left and right subtrees of the binary tree If the left depth is greater than the right depth, it means that the right side is full. The number of full nodes is 2 to the power of n - 1, plus the root is 2 to the power of n, and continue recursively on the left side.</description></item><item><title>669-Pruning a Binary Search Tree</title><link>https://siqi-liu.com/en/post/669-pruning-a-binary-search-tree/</link><pubDate>Thu, 11 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/669-pruning-a-binary-search-tree/</guid><description>#669. Pruning a binary search tree Release Date: March 11, 2021 Time: 20 minutes Similar to the previous question, most of them are divided into situations where the parent node is in the interval and not in the interval var trimBST = function(root, low, high) { var add = function (root,node) { if (!node || !root) return null if (node.val &gt; root.val ) { if (!root.right) { root.right = node } else { add(root.right,node) } } if (node.val &lt; root.val) { if (!root.left) { root.left = node } else { add(root.left,node) } } } var walk = function (root) { if (!root) return root if (root.val &lt; low || root.val &gt; high) { var left = walk(root.left) var right = walk(root.right) if (!left &amp;&amp; !right) { root = null } else if (right &amp;&amp; left) { root = right add(root,left) } else if (left) { root = left } else { root = right } } else { root.left= walk(root.left) root.right = walk(root.right) } return root } return walk(root) };After reading the analysis, I found that it can be simpler. The idea is that if it is greater than the right boundary, look directly in the left branch; if it is less than the left boundary, look directly in the right branch. This saves the step of deleting the node.</description></item><item><title>450-Delete a node in a binary search tree</title><link>https://siqi-liu.com/en/post/450-delete-a-node-in-a-binary-search-tree/</link><pubDate>Thu, 11 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/450-delete-a-node-in-a-binary-search-tree/</guid><description>Time: 30 minutes The question is divided into two parts to be solved, search and delete The search part is to find the node. You can find the required node according to the properties of the binary search tree. There are three types of deletion If there is only a left child, replace it with the left child. If there is only a right child, replace it with the right child. If there is neither child, assign null. (Since there was a recursive assignment earlier, this will succeed.) If there are both children, store the left child, replace it with the right child, and then find the left child’s position on the right. var deleteNode = function(root, key) { function insert(root,node) { if (root.val &gt; node.val) { if (!root.left) { root.left = node } else { insert(root.left,node) } } else { if (!root.right) { root.right = node } else { insert(root.right,node) } } } function search(root) { if (!root) { return null } if (root.val &gt; key) { root.left = search(root.left) } else if (root.val &lt; key){ root.right = search(root.right) } else { if (!root.left &amp;&amp; !root.right) { root = null } else if (root.left &amp;&amp; root.right) { var left = root.left root = root.right insert(root,left) } else if (root.left) { root = root.left } else if (root.right) { root = root.right } } return root } return search(root) };Points to note</description></item><item><title>116-Fill in the next right node pointer of each node</title><link>https://siqi-liu.com/en/post/116-fill-in-the-next-right-node-pointer-of-each-node/</link><pubDate>Wed, 10 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/116-fill-in-the-next-right-node-pointer-of-each-node/</guid><description>Time: 25 minutes The main idea is to use the stack. The difference from the ordinary level-order traversal is that the stack is cleared every time var connect = function(root) { if (!root) return null var stack = [root] while(stack.length) { var _stack = [...stack,null] stack = [] var pre = _stack.shift() while(_stack.length || pre) { pre.left &amp;&amp; stack.push(pre.left) pre.right &amp;&amp; stack.push(pre.right) pre.next = _stack.shift() pre = pre.next } } return root};Obviously, the memory space of On I used does not meet the constant space requirement of the question, considering that the links of each layer can be found in the form of a linked list by relying on the parent node.</description></item><item><title>1008-Pre-order traversal to construct a binary search tree</title><link>https://siqi-liu.com/en/post/1008-pre-order-traversal-to-construct-a-binary-search-tree/</link><pubDate>Wed, 10 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/1008-pre-order-traversal-to-construct-a-binary-search-tree/</guid><description>Time: Not done The main reason I didn’t make it was that I kept thinking about how to use a stack. When I looked at the answer to the stack later, I found that recursion was the simplest. recursion The idea is very simple. First, write out how to insert a child node. If the node is smaller than the parent node and the parent node’s left node is empty, make it the left node. If the node is larger than the parent node and the parent node’s right node is empty, make it the right node. If the node is smaller than the parent node, assign the parent node to the parent node’s left node and return to 1. If the node is larger than the parent node, assign the parent node to the parent node’s right node and return to 1. Traverse the entire array and insert each node one by one to get the result. var bstFromPreorder = function(preorder) { var add = function (node,val) { if (val &lt; node.val &amp;&amp; !node.left) { node.left = new TreeNode(val) } if (val &gt; node.val &amp;&amp; !node.right) { node.right = new TreeNode(val) } if (val &lt; node.val) { add(node.left,val) } if (val &gt; node.val) { add(node.right,val) } } var root = new TreeNode(preorder.shift()) for(let i = 0 ; i &lt; preorder.length ; i ++) { add(root,preorder[i]) } return root};Time: Not done</description></item><item><title>894-All possible full binary trees</title><link>https://siqi-liu.com/en/post/894-all-possible-full-binary-trees/</link><pubDate>Sun, 07 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/894-all-possible-full-binary-trees/</guid><description>Time: I copied the answers and finished it. It is easy to see that the idea is to use recursion, but the coding is the real problem. What we need to return is the root node, but the recursion is from bottom to top Try to solve it using dynamic programming, where dp(n) is the combination of dp(x) and dp (n - x - 1) var allPossibleFBT = function(n) { var dp = [] var buld = function (n) { for(let i = 1 ; i &lt;= n ; i ++ ) { if (i === 1) { dp[i] = new TreeNode(0) } else if (i % 2 === 0) { dp[i] = undefined } else { dp[i] = [] for(let left = 1; left &lt; i; left ++) { var leftNodes = dp[left] var rightNodes = dp[i - left - 1] for(let j = 0 ; j &lt; leftNodes.length ; j ++) { for(let k = 0 ; k &lt; rightNodes.length ; k ++) { var node = new TreeNode(0) node.left = leftNodes[j] node.right = rightNodes[k] dp[i].push(node) } } } } } } buld(n) return dp[n] };</description></item><item><title>297-Serialization and Deserialization of Binary Trees</title><link>https://siqi-liu.com/en/post/297-serialization-and-deserialization-of-binary-trees/</link><pubDate>Thu, 04 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/297-serialization-and-deserialization-of-binary-trees/</guid><description>Time: 30 minutes Serialization is simple and can be solved using BFS Deserialization requires the use of the properties of a binary tree, that is, the child nodes of the i-th node are (i + 1) * 2 - 1 and (i + 1) * 2 respectively. Find the parent node and push it onto the stack. At this point, pointer i is at the parent node’s val. Pop the parent node from the stack and find the parent node’s left and right nodes. The pointers find their values twice according to the rules. Push the left and right nodes onto the stack. i++ Repeat 1. var serialize = function(root) { if (!root) return [] var que = [root] var res = [] while(que.length) { var cur = que.shift() if (cur) { res.push(cur.val); que.push(cur.left); que.push(cur.right); } else { res.push('null'); } } return res.join(',') };/** * Decodes your encoded data to tree. * * @param {string} data * @return {TreeNode} */var deserialize = function(data) { if (!data.length) return null var nodes = data.split(',') var i = 0 var root = new TreeNode(nodes[i]) var que = [root] while ( que.length) { var node = que.shift() var left = nodes[ (i + 1) * 2 - 1] var right = nodes[ (i + 1) * 2] if (left !== 'null') { node.left = new TreeNode(left) que.push(node.left) } else { node.left = null } if (right !== 'null') { node.right = new TreeNode(right) que.push(node.right) } else { node.right = null } i++ } return root};</description></item><item><title>1372-Longest Alternating Path in a Binary Tree</title><link>https://siqi-liu.com/en/post/1372-longest-alternating-path-in-a-binary-tree/</link><pubDate>Mon, 01 Mar 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/1372-longest-alternating-path-in-a-binary-tree/</guid><description>Time: 25 minutes In fact, this is a relatively common DFS type question. The reason why it took so long is because there was a problem in judging the boundary value. When starting from the root, since the root may not have child nodes, the len value is 0 Starting from the child node, since the child nodes have been judged, it is considered that there is an edge of length 1 from the current node to the next node, so it is 1</description></item><item><title>Summary of Binary Trees</title><link>https://siqi-liu.com/en/post/summary-of-binary-trees/</link><pubDate>Sun, 28 Feb 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/summary-of-binary-trees/</guid><description>When traversing a binary tree in front, middle, or post-order, we use a stack to simplify operations. This is because they are all recursive structures of DFS, which means processing from bottom to top. However, I always start writing code from the root node, so I need a stack, and the stack is first-in-first-out. This way, I can process the root node last. Level-order traversal is BFS, from top to bottom. The root element that was enqueued first is also the one I want to process first. This is why DFS uses a stack and BFS uses a queue.</description></item><item><title>133-Path Sum II</title><link>https://siqi-liu.com/en/post/133-path-sum-ii/</link><pubDate>Sun, 28 Feb 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/133-path-sum-ii/</guid><description>Time: 10 minutes The question is to find the path from the root node to the child nodes whose sum is equal to the target value. It is easy to think of using DFS. The path can be passed as a parameter. As long as the last node is a leaf node, it can be used. var pathSum = function(root, sum) { var res = [] if (!root) return [] var dfs = function (node,visited,total) { if (sum === total &amp;&amp; (!node.left &amp;&amp; !node.right)) { res.push(visited) return } node.left &amp;&amp; dfs(node.left,[...visited,node.left.val],total + node.left.val) node.right &amp;&amp; dfs(node.right ,[...visited,node.right.val], total + node.right.val) } dfs(root,[root.val],root.val) return res };Time: 10 minutes</description></item><item><title>102 - Level-order Traversal of a Binary Tree</title><link>https://siqi-liu.com/en/post/102-level-order-traversal-of-a-binary-tree/</link><pubDate>Sun, 28 Feb 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/102-level-order-traversal-of-a-binary-tree/</guid><description>Techniques and examples for breadth-first (level-order) traversal of binary trees.</description></item><item><title>Two-color labeling</title><link>https://siqi-liu.com/en/post/two-color-labeling/</link><pubDate>Sat, 27 Feb 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/two-color-labeling/</guid><description>As you can see from the previous questions, the recursive methods for front-, middle-, and post-order traversal of a binary tree are similar, but the iterative implementation is completely different. Get inspired by the three-color marking method of garbage collection and find their common points Push the node onto the stack and mark it as 0 (unvisited). Pop the node off the stack. If it has been visited, pop it. If it has not been visited, mark it as visited and push it onto the stack. Continue with the left and right nodes to 1. In this way, we can use similar code to iteratively traverse a binary tree in front, middle, and back order by controlling the order in which we push the nodes onto the stack. All we need to do is create an additional On space to store the node status. Take post-order traversal as an example</description></item><item><title>145-Post-order traversal of a binary tree</title><link>https://siqi-liu.com/en/post/145-post-order-traversal-of-a-binary-tree/</link><pubDate>Fri, 26 Feb 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/145-post-order-traversal-of-a-binary-tree/</guid><description>1h The order of in-order traversal is left - right - center recursion It’s very easy with recursion var postorderTraversal = function(root) { var res = [] if (!root) return res var travel = function (node) { node.left &amp;&amp; travel(node.left) node.right &amp;&amp; travel(node.right) res.push(node.val) } travel(root) return res }; ```Iteration 1. Push the root node onto the stack. 1. Determine whether a node can be popped. If so, record itself as the node that was popped and pop it. 1. If a node cannot be popped, push the right and left nodes onto the stack. 1. Repeat step 2. ```javascript var postorderTraversal = function(root) { var stack = [root] var res = [] if (!root) { return res } var pre = root while(stack.length) { var node = stack[stack.length - 1] // When the left/right node of a node is the last node to be output, it means that both the left and right nodes have been output (because the root node is at the end of the post-order traversal) if ( (!node.left &amp;&amp; !node.right) || (node.left === pre || node.right === pre)) { // Only when there is no left or right node, or both left and right nodes have been output, can node = stack.pop() be output. pre = node res.push(node.val) } else { if (node.right) { stack.push(node.right) } if(node.left) { stack.push(node.left) } } } return res }; ```Summarize Although I have completed the forward, in-order, and post-order traversal of a binary tree, I have a feeling that I will forget it soon, especially the in-order and post-order traversal. I have not found any similarities between the two, so I will make a summary later. 1h The order of in-order traversal is left - right - center recursion It's very easy with recursion ```javascript var postorderTraversal = function(root) { var res = [] if (!root) return res var travel = function (node) { node.left &amp;&amp; travel(node.left) node.right &amp;&amp; travel(node.right) res.push(node.val) } travel(root) return res }; ```Iteration 1. Push the root node onto the stack. 1. Determine whether a node can be popped. If so, record itself as the node that was popped and pop it. 1. If a node cannot be popped, push the right and left nodes onto the stack. 1. Repeat step 2. ```javascript var postorderTraversal = function(root) { var stack = [root] var res = [] if (!root) { return res } var pre = root while(stack.length) { var node = stack[stack.length - 1] // When the left/right node of a node is the last node to be output, it means that both the left and right nodes have been output (because the root node is at the end of the post-order traversal) if ( (!node.left &amp;&amp; !node.right) || (node.left === pre || node.right === pre)) { // Only when there is no left or right node, or both left and right nodes have been output, can node = stack.pop() be output. pre = node res.push(node.val) } else { if (node.right) { stack.push(node.right) } if(node.left) { stack.push(node.left) } } } return res }; ```Summarize Although I've completed the forward, in-order, and post-order traversals of a binary tree, I have a feeling I'll soon forget them. This is especially true for the in-order and post-order traversals. I haven't found any similarities between them, so I'll summarize them later.</description></item><item><title>Understanding React Hooks</title><link>https://siqi-liu.com/en/post/understanding-react-hooks/</link><pubDate>Thu, 25 Feb 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/understanding-react-hooks/</guid><description>Understanding React Hooks Release Date: February 25, 2021 Understanding React Hooks Those who have used the old version of react should know that react’s class component has state to manage the internal state, as shown in the following example code class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() { return ( &lt;div&gt; &lt;h1&gt;Hello, world!&lt;/h1&gt; &lt;h2&gt;It is {this.state.date.toLocaleTimeString()}.&lt;/h2&gt; &lt;/div&gt; ); } }Function components do not have their own state, as shown in the following example code function Clock() { return ( &lt;div&gt; &lt;h1&gt;Hello, world!&lt;/h1&gt; &lt;h2&gt;It is {new Date().toLocaleTimeString()}.&lt;/h2&gt; &lt;/div&gt; ) }If I want to use a function component and want to have manual control over the date, I have to modify the component using props as follows, which transfers control to the parent component:</description></item><item><title>94-In-order traversal of a binary tree</title><link>https://siqi-liu.com/en/post/94-in-order-traversal-of-a-binary-tree/</link><pubDate>Thu, 25 Feb 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/94-in-order-traversal-of-a-binary-tree/</guid><description>30min The order of in-order traversal is left - middle - right recursion It’s very easy with recursion var inorderTraversal = function(root) { var res = [] if (!root) { return res } var travel = function (node) { node.left &amp;&amp; travel(node.left) res.push(node.val) node.right &amp;&amp; travel(node.right) } travel(root) return res }; ```Iteration The iterative steps are more complicated because the root node is not output first, so the root node needs to be retained 1. Push the root node onto the stack and check if it has a left child. If so, continue pushing until you reach a leaf node. 1. Pop the stack, output, and check if it has a right child. If so, push it onto the stack and continue with step 2. ```javascript var inorderTraversal = function(root) { var stack = [] var res = [] if (!root) return res stack.push(root) while(root.left) { stack.push(root.left) root = root.left } while(stack.length) { // At this point the top of the stack is the leftmost node in the tree var node = stack.pop() res.push(node.val) // There is a right node, push it into the stack and continue to look for the left node if (node.right) { node = node.right stack.push(node) while(node.left) { stack.push(node.left) node = node.left } } } return res };</description></item><item><title>215. Kth Largest Element in an Array</title><link>https://siqi-liu.com/en/post/215-kth-largest-element-in-an-array/</link><pubDate>Thu, 25 Feb 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/215-kth-largest-element-in-an-array/</guid><description>30min The first thing that comes to mind when I get the question is to sort it directly… But we can optimize the quick sort to get the result Solution 1. Quick sort The idea of quick sort is to find a benchmark in the array and divide the array into the benchmark, the part smaller than the benchmark, and the part larger than the benchmark. The benchmark itself has been sorted. If the benchmark is the kth largest element, the result can be obtained directly.</description></item><item><title>144-Pre-order traversal of a binary tree</title><link>https://siqi-liu.com/en/post/144-pre-order-traversal-of-a-binary-tree/</link><pubDate>Thu, 25 Feb 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/144-pre-order-traversal-of-a-binary-tree/</guid><description>10min The order of pre-order traversal of a binary tree is center-left-right First traverse all root nodes and left nodes, then process the right node It can be seen that this is a recursive behavior. Recursive problems can be simplified using stacks. Iterative solution var preorderTraversal = function(root) { if (!root) return null var stack = [root] var res = [] while(stack.length) { var node = stack.pop() res.push(node.val) node.right &amp;&amp; stack.push(node.right) node.left &amp;&amp; stack.push(node.left) } return res };Recursive solution Recursive problems can of course be solved recursively var preorderTraversal = function(root) { var res = [] if (!root) return res var travel = function (node) { res.push(node.val) node.left &amp;&amp; travel(node.left) node.right &amp;&amp; travel(node.right) } travel(root) return res };10min</description></item><item><title>Review of login and registration requirements</title><link>https://siqi-liu.com/en/post/review-of-login-and-registration-requirements/</link><pubDate>Sun, 21 Feb 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/review-of-login-and-registration-requirements/</guid><description>A few years ago, the company needed to log in and register, and the estimated construction period was one month. As a result, the project became uncontrollable during the process, and it took almost three months to complete. In order not to waste the overtime work during this period, I reviewed the process of completing the project. About Requirements Review Let’s briefly review the requirements first. Registration/login has three channels: account/password, mobile phone number, and three-party (including WeChat QR code scanning, QQ authorization, and Weibo authorization). Through a series of rules and guidance, you will eventually reach the login/registration success page and then jump to the source web page.</description></item><item><title>105-Constructing a binary tree from pre-order and in-order traversal sequences-1</title><link>https://siqi-liu.com/en/post/105-constructing-a-binary-tree-from-pre-order-and-in-order-traversal-sequences-1/</link><pubDate>Wed, 27 Jan 2021 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/105-constructing-a-binary-tree-from-pre-order-and-in-order-traversal-sequences-1/</guid><description>Time: 40 minutes ####105. Construct a binary tree from pre-order and in-order traversal sequences recursion Pre-order traversal: center-left-right In-order traversal: left-middle-right Therefore, we can first find the root element from the pre-order traversal, and then determine the number of left and right subtrees from the in-order traversal. var buildTree = function(preorder, inorder) { if (preorder.length === 0 || inorder.length=== 0) return null let nodeVal = preorder.shift() let node = new TreeNode(nodeVal) let index = inorder.indexOf(nodeVal) node.left = buildTree(preorder.slice(0,index), inorder.slice(0,index)) node.right = buildTree(preorder.slice(index),inorder.slice(index + 1)) return node }; ```Optimization Slices are very performance-intensive. In fact, there is no need to pass arrays. Functions can just pass pointers. ```javascript var buildTree = function(preorder, inorder) { var helper = function (p_start,p_end,i_start,i_end) { if (p_start &gt; p_end || i_start &gt; i_end ) return null let nodeVal = preorder[p_start] let node = new TreeNode(nodeVal) let index = inorder.indexOf(nodeVal) let left = index - i_start node.left = helper(p_start + 1 , p_start + left , i_start ,index - 1) node.right = helper(p_start + left + 1,p_end, index + 1,i_end) return node } return helper(0,preorder.length - 1,0,preorder.length - 1) };Summarize:</description></item><item><title>Hexo upgraded to 5</title><link>https://siqi-liu.com/en/post/hexo-upgraded-to-5/</link><pubDate>Fri, 11 Dec 2020 12:37:55 +0000</pubDate><guid>https://siqi-liu.com/en/post/hexo-upgraded-to-5/</guid><description>Filling Diary</description></item><item><title>Update after a year</title><link>https://siqi-liu.com/en/post/update-after-a-year/</link><pubDate>Fri, 11 Dec 2020 00:17:30 +0000</pubDate><guid>https://siqi-liu.com/en/post/update-after-a-year/</guid><description>One month after leaving Dahua</description></item><item><title>CSS pseudo-class selector nth-child</title><link>https://siqi-liu.com/en/post/css-pseudo-class-selector-nth-child/</link><pubDate>Thu, 07 Mar 2019 17:32:19 +0000</pubDate><guid>https://siqi-liu.com/en/post/css-pseudo-class-selector-nth-child/</guid><description>About nth-child and HTML specifications</description></item><item><title>Vue + express + mongodb build a backend login system</title><link>https://siqi-liu.com/en/post/vue-express-mongodb-build-a-backend-login-system/</link><pubDate>Thu, 13 Dec 2018 18:15:10 +0000</pubDate><guid>https://siqi-liu.com/en/post/vue-express-mongodb-build-a-backend-login-system/</guid><description>Keywords nodejs vue express mongodb</description></item><item><title>Ajax data transmission optimization</title><link>https://siqi-liu.com/en/post/ajax-data-transmission-optimization/</link><pubDate>Wed, 28 Nov 2018 14:47:40 +0000</pubDate><guid>https://siqi-liu.com/en/post/ajax-data-transmission-optimization/</guid><description>High Performance Javascript Knowledge Points</description></item><item><title>UI interface response optimization</title><link>https://siqi-liu.com/en/post/ui-interface-response-optimization/</link><pubDate>Thu, 22 Nov 2018 16:55:21 +0000</pubDate><guid>https://siqi-liu.com/en/post/ui-interface-response-optimization/</guid><description>High Performance Javascript Knowledge Points</description></item><item><title>Regular expression performance optimization</title><link>https://siqi-liu.com/en/post/regular-expression-performance-optimization/</link><pubDate>Tue, 06 Nov 2018 15:48:14 +0000</pubDate><guid>https://siqi-liu.com/en/post/regular-expression-performance-optimization/</guid><description>High Performance Javascript Knowledge Points</description></item><item><title>Algorithm and process control optimization</title><link>https://siqi-liu.com/en/post/algorithm-and-process-control-optimization/</link><pubDate>Thu, 25 Oct 2018 14:33:59 +0000</pubDate><guid>https://siqi-liu.com/en/post/algorithm-and-process-control-optimization/</guid><description>High Performance Javascript Knowledge Points</description></item><item><title>Performance optimization of DOM operations</title><link>https://siqi-liu.com/en/post/performance-optimization-of-dom-operations/</link><pubDate>Wed, 12 Sep 2018 15:09:33 +0000</pubDate><guid>https://siqi-liu.com/en/post/performance-optimization-of-dom-operations/</guid><description>High Performance Javascript Knowledge Points</description></item><item><title>Summary of Vue's easy-to-error and easy-to-confuse knowledge points</title><link>https://siqi-liu.com/en/post/summary-of-vue-s-easy-to-error-and-easy-to-confuse-knowledge-points/</link><pubDate>Mon, 10 Sep 2018 18:30:10 +0000</pubDate><guid>https://siqi-liu.com/en/post/summary-of-vue-s-easy-to-error-and-easy-to-confuse-knowledge-points/</guid><description>Knowledge Points Summary</description></item><item><title>JavaScript Loading Optimization</title><link>https://siqi-liu.com/en/post/javascript-loading-optimization/</link><pubDate>Tue, 04 Sep 2018 09:23:11 +0000</pubDate><guid>https://siqi-liu.com/en/post/javascript-loading-optimization/</guid><description>Notes from 'High Performance JavaScript'</description></item><item><title>DOM event flow</title><link>https://siqi-liu.com/en/post/dom-event-flow/</link><pubDate>Wed, 29 Aug 2018 17:29:45 +0000</pubDate><guid>https://siqi-liu.com/en/post/dom-event-flow/</guid><description>DOM event flow is easy to confuse</description></item><item><title>Arrays, stacks, queues</title><link>https://siqi-liu.com/en/post/arrays-stacks-queues/</link><pubDate>Wed, 22 Aug 2018 15:09:45 +0000</pubDate><guid>https://siqi-liu.com/en/post/arrays-stacks-queues/</guid><description>Javascript Data Structures</description></item><item><title>Proxy implementation of data response</title><link>https://siqi-liu.com/en/post/proxy-implementation-of-data-response/</link><pubDate>Fri, 27 Jul 2018 15:56:49 +0000</pubDate><guid>https://siqi-liu.com/en/post/proxy-implementation-of-data-response/</guid><description>Javascript</description></item><item><title>HTTP Protocol Summary</title><link>https://siqi-liu.com/en/post/http-protocol-summary/</link><pubDate>Mon, 23 Jul 2018 23:29:19 +0000</pubDate><guid>https://siqi-liu.com/en/post/http-protocol-summary/</guid><description>HTTP simple organization</description></item><item><title>ES5-Inheritance</title><link>https://siqi-liu.com/en/post/es5-inheritance/</link><pubDate>Tue, 17 Jul 2018 09:57:34 +0000</pubDate><guid>https://siqi-liu.com/en/post/es5-inheritance/</guid><description>ES5 knowledge review</description></item><item><title>ES5 - Creating Objects</title><link>https://siqi-liu.com/en/post/es5-creating-objects/</link><pubDate>Fri, 13 Jul 2018 16:51:52 +0000</pubDate><guid>https://siqi-liu.com/en/post/es5-creating-objects/</guid><description>ES5 knowledge review</description></item><item><title>async</title><link>https://siqi-liu.com/en/post/async/</link><pubDate>Wed, 11 Jul 2018 14:47:05 +0000</pubDate><guid>https://siqi-liu.com/en/post/async/</guid><description>"ES6 Standard Introduction" Knowledge Points Summary</description></item><item><title>Generator functions and applications</title><link>https://siqi-liu.com/en/post/generator-functions-and-applications/</link><pubDate>Fri, 06 Jul 2018 18:37:55 +0000</pubDate><guid>https://siqi-liu.com/en/post/generator-functions-and-applications/</guid><description>"ES6 Standard Introduction" Knowledge Points Summary</description></item><item><title>A Brief Introduction to Web Security</title><link>https://siqi-liu.com/en/post/a-brief-introduction-to-web-security/</link><pubDate>Thu, 05 Jul 2018 10:05:36 +0000</pubDate><guid>https://siqi-liu.com/en/post/a-brief-introduction-to-web-security/</guid><description>Web security related content</description></item><item><title>promise</title><link>https://siqi-liu.com/en/post/promise/</link><pubDate>Wed, 27 Jun 2018 13:18:47 +0000</pubDate><guid>https://siqi-liu.com/en/post/promise/</guid><description>"ES6 Standard Introduction" Knowledge Points Summary</description></item><item><title>Javascript deep copy implementation</title><link>https://siqi-liu.com/en/post/javascript-deep-copy-implementation/</link><pubDate>Tue, 26 Jun 2018 17:01:50 +0000</pubDate><guid>https://siqi-liu.com/en/post/javascript-deep-copy-implementation/</guid><description>Javascript Basics</description></item><item><title>Javascript sorting algorithm</title><link>https://siqi-liu.com/en/post/javascript-sorting-algorithm/</link><pubDate>Mon, 25 Jun 2018 18:48:42 +0000</pubDate><guid>https://siqi-liu.com/en/post/javascript-sorting-algorithm/</guid><description>Javascript algorithm sorting algorithm</description></item><item><title>proxy</title><link>https://siqi-liu.com/en/post/proxy/</link><pubDate>Fri, 18 May 2018 09:59:26 +0000</pubDate><guid>https://siqi-liu.com/en/post/proxy/</guid><description>"ES6 Standard Introduction" Knowledge Points Summary</description></item><item><title>Observer mode and Vue monitoring object changes</title><link>https://siqi-liu.com/en/post/observer-mode-and-vue-monitoring-object-changes/</link><pubDate>Sat, 05 May 2018 22:38:54 +0000</pubDate><guid>https://siqi-liu.com/en/post/observer-mode-and-vue-monitoring-object-changes/</guid><description>Javascript Design Patterns Knowledge Points</description></item><item><title>Set and Map Data Structures</title><link>https://siqi-liu.com/en/post/set-and-map-data-structures/</link><pubDate>Wed, 02 May 2018 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/set-and-map-data-structures/</guid><description>"ES6 Standard Introduction" Knowledge Points Summary</description></item><item><title>Object Expansion</title><link>https://siqi-liu.com/en/post/object-expansion/</link><pubDate>Tue, 24 Apr 2018 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/object-expansion/</guid><description>"ES6 Standard Introduction" Knowledge Points Summary</description></item><item><title>Iterator pattern</title><link>https://siqi-liu.com/en/post/iterator-pattern/</link><pubDate>Fri, 20 Apr 2018 09:41:05 +0000</pubDate><guid>https://siqi-liu.com/en/post/iterator-pattern/</guid><description>Javascript Design Patterns Knowledge Points</description></item><item><title>Proxy Mode</title><link>https://siqi-liu.com/en/post/proxy-mode/</link><pubDate>Thu, 19 Apr 2018 09:46:11 +0000</pubDate><guid>https://siqi-liu.com/en/post/proxy-mode/</guid><description>Javascript Design Patterns Knowledge Points</description></item><item><title>Js singleton pattern</title><link>https://siqi-liu.com/en/post/js-singleton-pattern/</link><pubDate>Fri, 13 Apr 2018 20:06:30 +0000</pubDate><guid>https://siqi-liu.com/en/post/js-singleton-pattern/</guid><description>Javascript Design Patterns Knowledge Points</description></item><item><title>Function extension</title><link>https://siqi-liu.com/en/post/function-extension/</link><pubDate>Thu, 12 Apr 2018 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/function-extension/</guid><description>"ES6 Standard Introduction" Knowledge Points Summary</description></item><item><title>Array expansion</title><link>https://siqi-liu.com/en/post/array-expansion/</link><pubDate>Wed, 11 Apr 2018 00:00:00 +0000</pubDate><guid>https://siqi-liu.com/en/post/array-expansion/</guid><description>"ES6 Standard Introduction" Knowledge Points Summary</description></item><item><title>Destructuring assignment of variables</title><link>https://siqi-liu.com/en/post/destructuring-assignment-of-variables/</link><pubDate>Tue, 10 Apr 2018 11:07:34 +0000</pubDate><guid>https://siqi-liu.com/en/post/destructuring-assignment-of-variables/</guid><description>"ES6 Standard Introduction" Knowledge Points Summary</description></item></channel></rss>