diff --git a/src/codeTemplates/backtrack.js b/src/codeTemplates/backtrack.js index 42dbfe1..4d60b67 100644 --- a/src/codeTemplates/backtrack.js +++ b/src/codeTemplates/backtrack.js @@ -65,18 +65,30 @@ module.exports = () => ({ text: ` const visited = {} function backtrack(i) { - if (满足特定条件){ + // 如果满足条件 + if (Meet certain conditions) { // 返回结果 or 退出搜索空间 + // return result or exit search space } - visited[i] = true // 将当前状态标为已搜索 - dosomething(i) // 对i做一些操作 - for (根据i能到达的下个状态j) { - if (!visited[j]) { // 如果状态j没有被搜索过 + // 将当前状态标为已搜索 + // mark the current state as searched + visited[i] = true + // 对i做一些操作 + // do something with i + dosomething(i) + + // for (根据i能到达的下个状态j) { + for (The next state j that can be reached based on i.) { + // 如果状态j没有被搜索过 + // if state j has not been searched + if (!visited[j]) { dfs(j) } } - undo(i) // 恢复i + // 恢复i + // restore i + undo(i) } backtrack(0) `, diff --git a/src/codeTemplates/bfs.js b/src/codeTemplates/bfs.js index f18e64e..4f91c2b 100644 --- a/src/codeTemplates/bfs.js +++ b/src/codeTemplates/bfs.js @@ -32,15 +32,20 @@ export default () => ({ class Solution: def bfs(k): # 使用双端队列,而不是数组。因为数组从头部删除元素的时间复杂度为 N,双端队列的底层实现其实是链表。 + # Utilize a double-ended queue instead of an array, as the time complexity for removing elements from the head of an array is O(N), whereas a double-ended queue, implemented as a linked list, offers a more efficient alternative. queue = collections.deque([root]) # 记录层数 + # Record the level or depth. steps = 0 # 需要返回的节点 + # The nodes to return. ans = [] # 队列不空,生命不止! + # While the queue is not empty, we continue. while queue: size = len(queue) # 遍历当前层的所有节点 + # Traverse all the nodes in the current level. for _ in range(size): node = queue.popleft() if (steps == k) ans.append(node) @@ -49,6 +54,7 @@ export default () => ({ if node.left: queue.append(node.left) # 遍历完当前层所有的节点后 steps + 1 + # After traversing all the nodes in the current level, steps + 1. steps += 1 return ans `, @@ -72,12 +78,15 @@ export default () => ({ class Solution: def bfs(k): # 使用双端队列,而不是数组。因为数组从头部删除元素的时间复杂度为 N,双端队列的底层实现其实是链表。 + # Utilize a double-ended queue instead of an array, as the time complexity for removing elements from the head of an array is O(N), whereas a double-ended queue, implemented as a linked list, offers a more efficient alternative. queue = collections.deque([root]) # 队列不空,生命不止! + # While the queue is not empty, we continue. while queue: node = queue.popleft() # 由于没有记录 steps,因此我们肯定是不需要根据层的信息去判断的。否则就用带层的模板了。 - if (node 是我们要找到的) return node + # Since we don't record steps, we don't need to judge based on the level information. Otherwise, we would use the template with level information. + if (node is what we are looking for) return node if node.right: queue.append(node.right) if node.left: diff --git a/src/codeTemplates/binarySearch.js b/src/codeTemplates/binarySearch.js index c1a5b8a..4c1cb45 100644 --- a/src/codeTemplates/binarySearch.js +++ b/src/codeTemplates/binarySearch.js @@ -20,6 +20,7 @@ module.exports = () => ({ text: ` public int binarySearch(int[] nums, int target) { // 左右都闭合的区间 [l, r] + // A closed interval [l, r] with both ends inclusive. int left = 0; int right = nums.length - 1; @@ -29,9 +30,11 @@ module.exports = () => ({ return mid; if (nums[mid] < target) // 搜索区间变为 [mid+1, right] + // Narrow down the search range to [mid+1, right] left = mid + 1; if (nums[mid] > target) // 搜索区间变为 [left, mid - 1] + // Narrow down the search range to [left, mid - 1] right = mid - 1; } return -1; @@ -42,13 +45,16 @@ module.exports = () => ({ text: ` def binarySearch(nums, target): # 左右都闭合的区间 [l, r] + # A closed interval [l, r] with both ends inclusive. l, r = 0, len(nums) - 1 while l <= r: mid = (left + right) >> 1 if nums[mid] == target: return mid # 搜索区间变为 [mid+1, right] + # Narrow down the search range to [mid+1, right] if nums[mid] < target: l = mid + 1 # 搜索区间变为 [left, mid - 1] + # Narrow down the search range to [left, mid - 1] if nums[mid] > target: r = mid - 1 return -1`, }, @@ -63,9 +69,11 @@ module.exports = () => ({ if (nums[mid] == target) return mid; if (nums[mid] < target) // 搜索区间变为 [mid+1, right] + // Narrow down the search range to [mid+1, right] left = mid + 1; if (nums[mid] > target) // 搜索区间变为 [left, mid - 1] + // Narrow down the search range to [left, mid - 1] right = mid - 1; } return -1; @@ -83,9 +91,11 @@ module.exports = () => ({ int mid = left + ((right - left) >> 1); if(nums[mid] == target){ return mid; } // 搜索区间变为 [mid+1, right] + // Narrow down the search range to [mid+1, right] else if(nums[mid] < target) left = mid + 1; // 搜索区间变为 [left, mid - 1] + // Narrow down the search range to [left, mid - 1] else right = mid - 1; } @@ -116,20 +126,24 @@ module.exports = () => ({ text: ` public int binarySearchLeft(int[] nums, int target) { // 搜索区间为 [left, right] + // A closed interval [left, right] with both ends inclusive. int left = 0; int right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] < target) { // 搜索区间变为 [mid+1, right] + // Narrow down the search range to [mid+1, right] left = mid + 1; } if (nums[mid] >= target) { // 搜索区间变为 [left, mid-1] + // Narrow down the search range to [left, mid-1] right = mid - 1; } } // 检查是否越界 + // Check if it is out of bounds if (left >= nums.length || nums[left] != target) return -1; return left; @@ -140,12 +154,15 @@ module.exports = () => ({ text: ` def binarySearchLeft(nums, target): # 左右都闭合的区间 [l, r] + # A closed interval [l, r] with both ends inclusive. l, r = 0, len(nums) - 1 while l <= r: mid = (l + r) >> 1 # 搜索区间变为 [mid+1, right] + # Narrow down the search range to [mid+1, right] if nums[mid] < target: l = mid + 1 # 搜索区间变为 [left, mid - 1] + # Narrow down the search range to [left, mid - 1] if nums[mid] >= target: r = mid - 1 if l >= len(nums) or nums[l] != target: return -1 return l`, @@ -160,12 +177,15 @@ module.exports = () => ({ const mid = Math.floor(left + (right - left) / 2); if (nums[mid] < target) // 搜索区间变为 [mid+1, right] + // Narrow down the search range to [mid+1, right] left = mid + 1; if (nums[mid] >= target) // 搜索区间变为 [left, mid - 1] + // Narrow down the search range to [left, mid - 1] right = mid - 1; } // 检查是否越界 + // Check if it is out of bounds if (left >= nums.length || nums[left] != target) return -1; return left; }`, @@ -175,23 +195,28 @@ module.exports = () => ({ text: ` int binarySearchLeft(vector& nums, int target) { // 搜索区间为 [left, right] + // The search interval is [left, right]. int left = 0, right = nums.size() - 1; while (left <= right) { int mid = left + ((right - left) >> 1); if (nums[mid] == target) { // 收缩右边界 + // Narrow down the right boundary right = mid - 1; } if (nums[mid] < target) { // 搜索区间变为 [mid+1, right] + // Narrow down the search range to [mid+1, right] left = mid + 1; } if (nums[mid] > target) { // 搜索区间变为 [left, mid-1] + // Narrow down the search range to [left, mid-1] right = mid - 1; } } // 检查是否越界 + // Check if it is out of bounds if (left >= nums.size() || nums[left] != target) return -1; return left; @@ -221,20 +246,24 @@ module.exports = () => ({ text: ` public int binarySearchRight(int[] nums, int target) { // 搜索区间为 [left, right] + // A closed interval [left, right] with both ends inclusive. int left = 0 int right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] <= target) { // 搜索区间变为 [mid+1, right] + // Narrow down the search range to [mid+1, right] left = mid + 1; } if (nums[mid] > target) { // 搜索区间变为 [left, mid-1] + // Narrow down the search range to [left, mid-1] right = mid - 1; } } // 检查是否越界 + // Check if it is out of bounds if (right < 0 || nums[right] != target) return -1; return right; @@ -245,12 +274,15 @@ module.exports = () => ({ text: ` def binarySearchRight(nums, target): # 左右都闭合的区间 [l, r] + # A closed interval [l, r] with both ends inclusive. l, r = 0, len(nums) - 1 while l <= r: mid = (l + r) >> 1 # 搜索区间变为 [mid+1, right] + # Narrow down the search range to [mid+1, right] if nums[mid] <= target: l = mid + 1 # 搜索区间变为 [left, mid - 1] + # Narrow down the search range to [left, mid - 1] if nums[mid] > target: r = mid - 1 if r < 0 or nums[r] != target: return -1 return r`, @@ -265,12 +297,15 @@ module.exports = () => ({ const mid = Math.floor(left + (right - left) / 2); if (nums[mid] <= target) // 搜索区间变为 [mid+1, right] + // Narrow down the search range to [mid+1, right] left = mid + 1; if (nums[mid] > target) // 搜索区间变为 [left, mid - 1] + // Narrow down the search range to [left, mid - 1] right = mid - 1; } // 检查是否越界 + // Check if it is out of bounds if (right < 0 || nums[right] != target) return -1; return right; }`, @@ -280,23 +315,28 @@ module.exports = () => ({ text: ` int binarySearchRight(vector& nums, int target) { // 搜索区间为 [left, right] + // The search interval is [left, right]. int left = 0, right = nums.size() - 1; while (left <= right) { int mid = left + ((right - left) >> 1); if (nums[mid] == target) { // 收缩左边界 + // Narrow down the left boundary left = mid + 1; } if (nums[mid] < target) { // 搜索区间变为 [mid+1, right] + // Narrow down the search range to [mid+1, right] left = mid + 1; } if (nums[mid] > target) { // 搜索区间变为 [left, mid-1] + // Narrow down the search range to [left, mid-1] right = mid - 1; } } // 检查是否越界 + // Check if it is out of bounds if (right < 0 || nums[right] != target) return -1; return right; @@ -315,8 +355,10 @@ module.exports = () => ({ text: ` def bisect_left(nums, x): # 内置 api + # built-in API bisect.bisect_left(nums, x) # 手写 + # Manually write l, r = 0, len(A) - 1 while l <= r: mid = (l + r) // 2 @@ -330,13 +372,14 @@ module.exports = () => ({ text: ` /** * @author suukii - * @description 寻找最左插入位置 + * @description ${t("Locale.codeTemplate.binarySearch.item4")} * @param {number[]} nums * @param {number} x * @returns {number} */ function searchInsertLeft(nums, x) { // 题意转换一下,其实就是寻找第一个“大于等于” x 的数字,返回它的下标 + // Change the meaning of the question, in fact, it is to find the first number "greater than or equal to" x and return its subscript let left = 0; let right = nums.length - 1; @@ -369,8 +412,10 @@ function searchInsertLeft(nums, x) { text: ` def bisect_right(nums, x): # 内置 api + # built-in API bisect.bisect_right(nums, x) # 手写 + # Manually write l, r = 0, len(A) - 1 while l <= r: mid = (l + r) // 2 @@ -383,13 +428,14 @@ function searchInsertLeft(nums, x) { language: "JS", text: ` /**@author suukii - * @description 寻找最右插入位置 + * @description ${t("Locale.codeTemplate.binarySearch.item5")} * @param {number[]} nums * @param {number} x * @returns {number} */ function searchInsertRight(nums, x) { // 题意转换一下,其实就是寻找第一个“大于” x 的数字,返回它的下标 + // Change the meaning of the question, in fact, it is to find the first number "greater than" x and return its subscript let left = 0; let right = nums.length - 1; diff --git a/src/codeTemplates/hand-writing.js b/src/codeTemplates/hand-writing.js index 480dfb8..cbdf37f 100644 --- a/src/codeTemplates/hand-writing.js +++ b/src/codeTemplates/hand-writing.js @@ -20,7 +20,9 @@ module.exports = () => ({ language: "py", text: ` # 1. 归并排序(推荐!其他排序方法都不推荐在竞赛中使用) +# 1. Merge sort (recommended! None of the other ranking methods are recommended for use in contests) # 归并排序乞丐版 +# Merge sort beggar version class Solution: def sortArray(self, nums: List[int]) -> List[int]: def mergeSort(l, r): @@ -49,6 +51,7 @@ class Solution: mergeSort(0, len(nums) - 1) return nums # 归并排序优化版 +# Merge sort optimization version class Solution: def sortArray(self, nums: List[int]) -> List[int]: temp = [0] * len(nums) @@ -83,7 +86,9 @@ class Solution: return nums # 2. 快速排序 +# 2. Quick sort # 快速排序乞丐版 +# Quick sort beggar version class Solution: def sortArray(self, nums: List[int]) -> List[int]: temp = [0] * len(nums) @@ -98,6 +103,7 @@ class Solution: return quickSort(nums) # 快速排序优化版 +# Quick sort optimization version class Solution: def sortArray(self, nums: List[int]) -> List[int]: temp = [0] * len(nums) @@ -126,6 +132,7 @@ class Solution: return nums # 3. 插入排序 +# 3. Insertion sort class Solution: def sortArray(self, nums: List[int]) -> List[int]: n = len(nums) @@ -139,6 +146,7 @@ class Solution: return nums # 4. 选择排序 +# 4. Selection sort class Solution: def sortArray(self, nums: List[int]) -> List[int]: n = len(nums) @@ -151,6 +159,7 @@ class Solution: return nums # 5. 冒泡排序 +# 5. Bubble sort class Solution: def sortArray(self, nums: List[int]) -> List[int]: n = len(nums) @@ -179,6 +188,7 @@ class Solution: language: "py", text: ` # 1. 归并排序(推荐!其他排序方法都不推荐在竞赛中使用) +# 1. Merge sort (recommended! None of the other ranking methods are recommended for use in contests) class Solution: def sortList(self, head: ListNode) -> ListNode: def mergeSort(head: ListNode) -> ListNode: @@ -213,9 +223,11 @@ class Solution: return mergeSort(head) # 2. 快速排序 +# 2. Quick sort class Solution: def sortList(self, head): # 最坏情况也是 n ^ 2 ,因此面试或者竞赛不建议使用 + # The worst case is also n ^ 2, so it is not recommended to use it in interviews or competitions def quickSort(head, end): if head != end: @@ -226,12 +238,15 @@ class Solution: def partition(head, end): # p1是写指针,p2是读指针 # 最终 p1 是大的链表的头, head 是小的链表的头 + # p1 is the write pointer, p2 is the read pointer + # Finally, p1 is the head of the larger linked list, and head is the head of the smaller linked list pivot_val = head.val p1, p2 = head, head.next while p2 != end: if p2.val < pivot_val: # 相当于数组的 append 方法 + # Equivalent to the append method of an array p1 = p1.next p1.val, p2.val = p2.val, p1.val p2 = p2.next @@ -241,6 +256,7 @@ class Solution: quickSort(head, None) return head # 3. 插入排序 +# 3. Insertion sort class Solution: def sortList(self, head): if head == None or head.next == None: @@ -252,14 +268,18 @@ class Solution: cur = head while cur: # 准备将 last 插入到合适位置 + # Prepare to insert last into the appropriate position last = cur.next if last and last.val < cur.val: # 从 dummy 到 cur 线性遍历找第一个满足条件的位置并插入 + # Linearly traverse from dummy to cur to find the first position that meets the conditions and insert while pre.next and pre.next.val < last.val: pre = pre.next tmp = pre.next pre.next = last - cur.next = last.next # 别忘了这个,否则成环 + # 别忘了这个,否则成环 + # Don't forget this, otherwise it will become a ring + cur.next = last.next last.next = tmp pre = dummy else: @@ -267,6 +287,7 @@ class Solution: return dummy.next # 4. 选择排序 +# 4. Selection sort class Solution: def sortList(self, head): temp = head @@ -282,6 +303,7 @@ class Solution: temp = temp.next return head # 5. 冒泡排序 +# 5. Bubble sort class Solution: def sortList(self, head): if not head: diff --git a/src/codeTemplates/heap.js b/src/codeTemplates/heap.js index 42fc19c..2ddd040 100644 --- a/src/codeTemplates/heap.js +++ b/src/codeTemplates/heap.js @@ -32,7 +32,7 @@ function minHeap(A = []) { }; minHeap.prototype.pop = function() { - if (this.h.length === 1) throw new Error('空了就别弹了吧?'); + if (this.h.length === 1) throw new Error("Don't pop it up when it's empty"); const ans = this.h[1]; this.h[1] = this.h[this.h.length - 1]; this.h.pop(); @@ -111,7 +111,7 @@ class min_heap: self.shift_down(i) i = i + 1 -# 使用: +# Use: h = min_heap([5, 6, 2, 3]) @@ -139,6 +139,17 @@ import java.util.Comparator; * build 构建堆 */ +/** + * en: + * Use a complete binary tree to construct a heap + * The starting point is 1 + * Then the child nodes are i <<1 and i<<1 + 1 + * The core methods are + * shiftdown exchange sinking + * shiftup exchange floating + *

+ * build build heap + */ public class MinHeap { int size = 0; @@ -166,6 +177,7 @@ public class MinHeap { while ((i << 1) <= size) { int child = i << 1; // child!=size 判断当前元素是否包含右节点 + // child!=size Determine if the current element contains a right node. if (child != size && queue[child + 1] < queue[child]) { child++; } diff --git a/src/codeTemplates/prime.js b/src/codeTemplates/prime.js index 254bcaa..bb4087d 100644 --- a/src/codeTemplates/prime.js +++ b/src/codeTemplates/prime.js @@ -2,7 +2,9 @@ const { t } = require("../locales"); const pyCode = ` MAXN = int(1e5) -flag = [True] * (MAXN + 10) # if flag[i] is true, then i is prime +# 如果 flag[i] 为 true,表示 i 是质数 +# if flag[i] is true, then i is prime +flag = [True] * (MAXN + 10) flag[0], flag[1] = False, False for i in range(2, int(MAXN ** 0.5) + 1): if flag[i]: diff --git a/src/codeTemplates/segmentTree.js b/src/codeTemplates/segmentTree.js index 7f4097f..6644b33 100644 --- a/src/codeTemplates/segmentTree.js +++ b/src/codeTemplates/segmentTree.js @@ -6,20 +6,33 @@ class SegmentTree: def __init__(self, data:List[int]): ''' data:传入的数组 + + --- en --- + data: the array to be passed in ''' self.data = data self.n = len(data) # 申请4倍data长度的空间来存线段树节点 - self.tree = [None] * (4 * self.n) # 索引i的左孩子索引为2i+1,右孩子为2i+2 + # Allocate 4 times the length of data to store the segment tree node + # 索引i的左孩子索引为2i+1,右孩子为2i+2 + # The index of the left child of index i is 2i+1, and the right child is 2i+2 + self.tree = [None] * (4 * self.n) if self.n: self.build(0, 0, self.n-1) # 本质就是一个自底向上的更新过程 # 因此可以使用后序遍历,即在函数返回的时候更新父节点。 + # It is essentially a bottom-up renewal process + # Therefore, post-order traversal can be used, that is, update the parent node when the function returns. def update(self, tree_index, l, r, index): ''' tree_index:某个根节点索引 l, r : 此根节点代表区间的左右边界 index : 更新的值的索引 + + --- en --- + tree_index: the index of a root node + l, r : the left and right boundaries of the interval represented by this root node + index : the index of the value to be updated ''' if l == r==index : self.tree[tree_index] = self.data[index] @@ -28,12 +41,16 @@ class SegmentTree: left, right = 2 * tree_index + 1, 2 * tree_index + 2 if index > mid: # 要更新的区间在右子树 + # The interval to be updated is in the right subtree self.update(right, mid+1, r, index) else: # 要更新的区间在左子树index<=mid + # The interval to be updated is in the left subtree index<=mid self.update(left, l, mid, index) # 查询区间一部分在左子树一部分在右子树 # 区间和使用加法即可,如果不是区间和要改下面这行代码 + # Part of the query interval is in the left subtree and part is in the right subtree + # The interval sum can be used for addition, if it is not the interval sum, the following line of code needs to be changed self.tree[tree_index] = self.tree[left] + self.tree[right] def updateSum(self,index:int,value:int): @@ -45,27 +62,41 @@ class SegmentTree: tree_index : 某个根节点的索引 l, r : 该节点表示的区间的左右边界 ql, qr: 待查询区间的左右边界 + + --- en --- + Recursively query the value of the interval [ql,..,qr] + tree_index : the index of a root node + l, r : the left and right boundaries of the interval represented by this root node + ql, qr: the left and right boundaries of the interval to be queried ''' if l == ql and r == qr: return self.tree[tree_index] # 区间中点,对应左孩子区间结束,右孩子区间开头 + # Interval midpoint, corresponding to the end of the left child interval, the beginning of the right child interval mid = (l+r) // 2 left, right = tree_index * 2 + 1, tree_index * 2 + 2 if qr <= mid: # 查询区间全在左子树 + # The query interval is all in the left subtree return self.query(left, l, mid, ql, qr) elif ql > mid: # 查询区间全在右子树 + # The query interval is all in the right subtree return self.query(right, mid+1, r, ql, qr) # 查询区间一部分在左子树一部分在右子树 # 区间和使用加法即可,如果不是区间和要改下面这行代码 + # Part of the query interval is in the left subtree and part is in the right subtree + # The interval sum can be used for addition, if it is not the interval sum, the following line of code needs to be changed return self.query(left, l, mid, ql, mid) + self.query(right, mid+1, r, mid+1, qr) def querySum(self, ql:int, qr:int) -> int: ''' 返回区间[ql,..,qr]的和 + + --- en --- + Returns the sum of the interval [ql,..,qr] ''' return self.query(0, 0, self.n-1, ql, qr) @@ -74,15 +105,25 @@ class SegmentTree: 递归创建线段树 tree_index : 线段树节点在数组中位置 l, r : 该节点表示的区间的左,右边界 + + --- en --- + Recursively create a segment tree + tree_index : the position of the segment tree node in the array + l, r : the left and right boundaries of the interval represented by this node ''' if l == r: self.tree[tree_index] = self.data[l] return - mid = (l+r) // 2 # 区间中点,对应左孩子区间结束,右孩子区间开头 - left, right = 2 * tree_index + 1, 2 * tree_index + 2 # tree_index的左右子树索引 + # 区间中点,对应左孩子区间结束,右孩子区间开头 + # Interval midpoint, corresponding to the end of the left child interval, the beginning of the right child interval + mid = (l+r) // 2 + # tree_index的左右子树索引 + # The left and right subtree indexes of tree_index + left, right = 2 * tree_index + 1, 2 * tree_index + 2 self.build(left, l, mid) self.build(right, mid+1, r) # 区间和使用加法即可,如果不是区间和要改下面这行代码 + # The interval sum can be used for addition, if it is not the interval sum, the following line of code needs to be changed self.tree[tree_index] = self.tree[left] + self.tree[right] `; @@ -132,14 +173,24 @@ export default () => ({ def __init__(self, data): ''' data:传入的数组 + + --- en --- + data: the array to be passed in ''' self.data = data self.n = len(data) - # 申请4倍data长度的空间来存线段树节点 - self.tree = [0] * (4 * self.n) # 索引i的左孩子索引为2i+1,右孩子为2i+2 + # 申请4倍data长度的空间来存线段树节点 + # Allocate 4 times the length of data to store the segment tree node + # 索引i的左孩子索引为2i+1,右孩子为2i+2 + # The index of the left child of index i is 2i+1, and the right child is 2i+2 + self.tree = [0] * (4 * self.n) # 要点 1 开始 - self.dirty = [True] * (4 * self.n) # 索引i的左孩子索引为2i+1,右孩子为2i+2 + # point 1 start + # 索引i的左孩子索引为2i+1,右孩子为2i+2 + # The index of the left child of index i is 2i+1, and the right child is 2i+2 + self.dirty = [True] * (4 * self.n) # 要点 1 结束 + # point 1 end if self.n: self.build(0, 0, self.n-1) @@ -159,18 +210,26 @@ export default () => ({ def update(self, tree_index, l, r, ql, qr, val): if l == ql and r == qr: # 要点 2 开始 + # point 2 start self.dirty[tree_index] = not self.dirty[tree_index] self.tree[tree_index] = (r - l + 1) * val # 要点 2 结束 + # point 2 end return left, right = 2 * tree_index + 1, 2 * tree_index + 2 mid = (l + r) // 2 # 要点 3 开始 - if not self.dirty[tree_index]: # 如果有标记就处理 + # point 3 start + # 如果有标记就处理 + # If there is a mark, process it + if not self.dirty[tree_index]: self.update(left, l, mid, l, mid, val) self.update(right, mid+1, r, mid+1, r, val) - self.dirty[tree_index] = True # 重置回去 + # 重置回去 + # Reset back + self.dirty[tree_index] = True # 要点 3 结束 + # point 3 end if qr <= mid: self.update(left, l, mid, ql, qr, val) elif ql > mid: self.update(right, mid+1, r, ql, qr, val) else: @@ -187,11 +246,17 @@ export default () => ({ left, right = 2 * tree_index + 1, 2 * tree_index + 2 mid = (l + r) // 2 # 要点 3 开始 - if not self.dirty[tree_index]: # 如果有标记就处理 + # point 3 start + # 如果有标记就处理 + # If there is a mark, process it + if not self.dirty[tree_index]: self.update(left, l, mid, l, mid) self.update(right, mid+1, r, mid+1, r) - self.dirty[tree_index] = True # 重置回去 + # 重置回去 + # Reset back + self.dirty[tree_index] = True # 要点 3 结束 + # point 3 end if qr <= mid: return self.query(left, l, mid, ql, qr) if ql > mid: return self.query(right, mid+1, r, ql, qr) return self.query(left, l, mid, ql, mid) + self.query(right, mid+1, r, mid+1, qr) @@ -217,19 +282,32 @@ class SegmentTree: def __init__(self, upper, lower): """ data:传入的数组 + + --- en --- + data: the array to be passed in """ self.lower = lower self.upper = upper # 申请4倍data长度的空间来存线段树节点 - self.tree = [0] * (4 * (upper - lower + 1)) # 索引i的左孩子索引为2i+1,右孩子为2i+2 + # Allocate 4 times the length of data to store the segment tree node + # 索引i的左孩子索引为2i+1,右孩子为2i+2 + # The index of the left child of index i is 2i+1, and the right child is 2i+2 + self.tree = [0] * (4 * (upper - lower + 1)) # 本质就是一个自底向上的更新过程 # 因此可以使用后序遍历,即在函数返回的时候更新父节点。 + # It is essentially a bottom-up renewal process + # Therefore, post-order traversal can be used, that is, update the parent node when the function returns. def update(self, tree_index, l, r, index): """ tree_index:某个根节点索引 l, r : 此根节点代表区间的左右边界 index : 更新的值的索引 + + --- en --- + tree_index: the index of a root node + l, r : the left and right boundaries of the interval represented by this root node + index : the index of the value to be updated """ if l > index or r < index: return @@ -250,10 +328,17 @@ class SegmentTree: tree_index : 某个根节点的索引 l, r : 该节点表示的区间的左右边界 ql, qr: 待查询区间的左右边界 + + --- en --- + Recursively query the value of the interval [ql,..,qr] + tree_index : the index of a root node + l, r : the left and right boundaries of the interval represented by this root node + ql, qr: the left and right boundaries of the interval to be queried """ if qr < l or ql > r: return 0 # l 和 r 在 [ql, qr] 内 + # l and r are within [ql, qr] if ql <= l and qr >= r: return self.tree[tree_index] mid = (l + r) // 2 @@ -263,6 +348,9 @@ class SegmentTree: def queryCount(self, ql: int, qr: int) -> int: """ 返回区间[ql,..,qr]的计数信息 + + --- en --- + Returns the count information of the interval [ql,..,qr] """ return self.query(0, self.lower, self.upper, ql, qr) `, @@ -285,37 +373,60 @@ class SegmentTree: text: ` class Node: def __init__(self, l, r): - self.left = None # 左孩子的指针 - self.right = None # 右孩子的指针 - self.l = l # 区间左端点 - self.r = r # 区间右端点 - self.m = (l + r) >> 1 # 中点 - self.v = 0 # 当前值 - self.add = 0 # 懒标记 + # 左孩子的指针 + # The pointer to the left child + self.left = None + # 右孩子的指针 + # The pointer to the right child + self.right = None + # 区间左端点 + # Interval left endpoint + self.l = l + # 区间右端点 + # Interval right endpoint + self.r = r + # 中点 + # Midpoint + self.m = (l + r) >> 1 + # 当前值 + # Current value + self.v = 0 + # 懒标记 + # Lazy tag + self.add = 0 class SegmentTree: def __init__(self,n): # 默认就一个根节点,不 build 出整个树,节省空间 - self.root = Node(0,n-1) # 根节点 + # There is only one root node by default, and the entire tree is not built to save space + self.root = Node(0,n-1) # Root Node def update(self, l, r, v, node): if l > node.r or r < node.l: return if l <= node.l and node.r <= r: node.v = (node.r - node.l + 1) * v - node.add = v # 做了一个标记 + # 做了一个标记 + # Made a mark + node.add = v return - self.__pushdown(node) # 动态开点。为子节点赋值,这个值就从 add 传递过来 + # 动态开点。为子节点赋值,这个值就从 add 传递过来 + # Dynamic opening. Assign values to child nodes, and this value is passed from add + self.__pushdown(node) self.update(l, r, v, node.left) - self.update(l, r, v, node.right) - self.__pushup(node) # 动态开点结束后,修复当前节点的值 + self.update(l, r, v, node.right) + # 动态开点结束后,修复当前节点的值 + # After the dynamic opening is completed, repair the value of the current node + self.__pushup(node) def query(self, l, r,node): if l > node.r or r < node.l: return 0 if l <= node.l and node.r <= r: return node.v - self.__pushdown(node) # 动态开点。为子节点赋值,这个值就从 add 传递过来 + # 动态开点。为子节点赋值,这个值就从 add 传递过来 + # Dynamic opening. Assign values to child nodes, and this value is passed from add + self.__pushdown(node) return self.query(l, r, node.left) + self.query(l, r, node.right) def __pushdown(self,node): diff --git a/src/codeTemplates/sliding-window.js b/src/codeTemplates/sliding-window.js index aba8270..b28ca7e 100644 --- a/src/codeTemplates/sliding-window.js +++ b/src/codeTemplates/sliding-window.js @@ -19,16 +19,17 @@ export default () => ({ codes: [ { language: "py", - text: ` - 初始化前后指针 = 0 - 初始化 ans + text: t("Locale.codeTemplate.slidingWindow.item1_text"), + // text: ` + // 初始化前后指针 = 0 + // 初始化 ans - for 前指针 in 可迭代集合 - 更新窗口内信息(前指针进窗口,后指针出窗口) - 后指针移动 - 更新答案 - 返回 ans - `, + // for 前指针 in 可迭代集合 + // 更新窗口内信息(前指针进窗口,后指针出窗口) + // 后指针移动 + // 更新答案 + // 返回 ans + // `, }, ], }, @@ -86,18 +87,19 @@ export default () => ({ codes: [ { language: "py", - text: ` - 初始化慢指针 = 0 - 初始化 ans + text: t("Locale.codeTemplate.slidingWindow.item2_text"), + // text: ` + // 初始化慢指针 = 0 + // 初始化 ans - for 快指针 in 可迭代集合 - 更新窗口内信息 - while 窗口内不符合题意 - 扩展或者收缩窗口 - 慢指针移动 - 更新答案 - 返回 ans - `, + // for 快指针 in 可迭代集合 + // 更新窗口内信息 + // while 窗口内不符合题意 + // 扩展或者收缩窗口 + // 慢指针移动 + // 更新答案 + // 返回 ans + // `, }, ], }, diff --git a/src/codeTemplates/trie.js b/src/codeTemplates/trie.js index 1898c0a..360fe8b 100644 --- a/src/codeTemplates/trie.js +++ b/src/codeTemplates/trie.js @@ -33,6 +33,7 @@ private: delete root; } public: + /** 在这里初始化您的数据结构。 */ /** Initialize your data structure here. */ Trie() { root = new TrieNode(); @@ -42,6 +43,7 @@ public: clear(root); } + /** 将一个单词插入到树中。 */ /** Inserts a word into the trie. */ void insert(string word) { TrieNode *p = root; @@ -54,12 +56,14 @@ public: p->isEnd = true; } + /** 返回单词是否在树中。 */ /** Returns if the word is in the trie. */ bool search(string word) { TrieNode *p = findString(word); return p != nullptr && p->isEnd; } + /** 返回树中是否有以给定前缀开头的任何单词。 */ /** Returns if there is any word in the trie that starts with the given prefix. */ bool startsWith(string prefix) { TrieNode *p = findString(prefix); @@ -93,12 +97,15 @@ type Trie struct { // return &Trie{root: NewNode(false)} //} + +/** 在这里初始化您的数据结构。 */ /** Initialize your data structure here. */ func Constructor() Trie { return Trie{root: NewNode(false)} } +/** 将一个单词插入到树中。 */ /** Inserts a word into the trie. */ func (t *Trie) Insert(word string) { cur := t.root @@ -110,12 +117,15 @@ func (t *Trie) Insert(word string) { } cur = cur.next[c] } - if !cur.isWord { // 标记为单词 + if !cur.isWord { + // 标记为单词 + // mark as word cur.isWord = true } } +/** 返回单词是否在树中。 */ /** Returns if the word is in the trie. */ func (t *Trie) Search(word string) bool { cur := t.root @@ -131,6 +141,7 @@ func (t *Trie) Search(word string) bool { } +/** 返回树中是否有以给定前缀开头的任何单词。 */ /** Returns if there is any word in the trie that starts with the given prefix. */ func (t *Trie) StartsWith(prefix string) bool { cur := t.root @@ -202,9 +213,12 @@ class Trie { } private class TrieNode { - - int count; //表示以该处节点构成的串的个数 - int preCount; //表示以该处节点构成的前缀的字串的个数 + // 表示以该处节点构成的串的个数 + // Represents the number of strings consisting of nodes at that point + int count; + // 表示以该处节点构成的前缀的字串的个数 + // Represents the number of substrings consisting of prefixes at that point + int preCount; TrieNode[] children; TrieNode() { @@ -267,8 +281,12 @@ export default () => ({ text: ` class TrieNode: def __init__(self): - self.count = 0 # 表示以该处节点构成的串的个数 - self.preCount = 0 # 表示以该处节点构成的前缀的字串的个数 + # 表示以该处节点构成的串的个数 + # Represents the number of strings consisting of nodes at that point + self.count = 0 + # 表示以该处节点构成的前缀的字串的个数 + # Represents the number of substrings consisting of prefixes at that point + self.preCount = 0 self.children = {} class Trie: @@ -307,8 +325,12 @@ class Trie: text: ` var Trie = function() { this.children = {}; - this.count = 0 //表示以该处节点构成的串的个数 - this.preCount = 0 // 表示以该处节点构成的前缀的字串的个数 + // 表示以该处节点构成的串的个数 + // Represents the number of strings consisting of nodes at that point + this.count = 0 + // 表示以该处节点构成的前缀的字串的个数 + // Represents the number of substrings consisting of prefixes at that point + this.preCount = 0 }; Trie.prototype.insert = function(word) { diff --git a/src/codeTemplates/uf.js b/src/codeTemplates/uf.js index 7a7ab99..be200e3 100644 --- a/src/codeTemplates/uf.js +++ b/src/codeTemplates/uf.js @@ -40,6 +40,7 @@ class UF: self.parent = {} self.cnt = 0 # 初始化 parent,size 和 cnt + # Initialize parent, size and cnt for i in range(M): self.parent[i] = i self.cnt += 1 @@ -78,6 +79,7 @@ class UF: class UF: def __init__(self, M): # 初始化 parent,weight + # Initialize parent, weight self.parent = {} self.weight = {} for i in range(M): diff --git a/src/locales/en.js b/src/locales/en.js index f9f8a4a..1ff0453 100644 --- a/src/locales/en.js +++ b/src/locales/en.js @@ -231,7 +231,29 @@ const en = { slidingWindow: { title: "Sliding Window", item1: "Fixed length sliding window", + item1_text:` + Initialize front and back pointers to 0. + Initialize ans. + + for front in iterable + update window info (front in, back out) + move back pointer + update ans + return ans + `, item2: "Variable length sliding window", + item2_text:` + Initialize the slow pointer to 0. + Initialize ans. + + for fast pointer in iterable collection + update information in the window + while the window does not satisfy the question + expand or shrink the window + move the slow pointer + update the answer + return ans + ` }, backtrack: { @@ -364,7 +386,8 @@ const en = { `, dp: "Dynamic Programming", - dp_desc: `The basic framework for different problems of the same type is generally consistent, but with slight variations in details. The template code is explained using a specific type as an example, and individuals should make adjustments based on the actual situation. + dp_desc: ` + The basic framework for different problems of the same type is generally consistent, but with slight variations in details. The template code is explained using a specific type as an example, and individuals should make adjustments based on the actual situation. The three key points for dynamic programming are: state, enumeration, and transition equations (choices). For each type of problem, I try to provide hints based on these three points. @@ -409,8 +432,6 @@ const en = { dp_item7: "Game type(List only the problems)", dp_item8: "Interval DP", - dp_item8_text_comment: - "Using memoization might lead to better code writing. For example, the above DP code can be transformed into memoized recursion as:", dp_item8_keys1: ` Traversing in reverse from the right boundary and in forward from the left boundary `, diff --git a/src/locales/zh.js b/src/locales/zh.js index 72aa22a..4fb8f84 100644 --- a/src/locales/zh.js +++ b/src/locales/zh.js @@ -224,7 +224,29 @@ const zh = { slidingWindow: { title: "滑动窗口", item1: "固定窗口(伪代码)", + item1_text:` + 初始化前后指针 = 0 + 初始化 ans + + for 前指针 in 可迭代集合 + 更新窗口内信息(前指针进窗口,后指针出窗口) + 后指针移动 + 更新答案 + 返回 ans + `, item2: "可变窗口(伪代码)", + item2_text:` + 初始化慢指针 = 0 + 初始化 ans + + for 快指针 in 可迭代集合 + 更新窗口内信息 + while 窗口内不符合题意 + 扩展或者收缩窗口 + 慢指针移动 + 更新答案 + 返回 ans + `, }, backtrack: { @@ -407,8 +429,6 @@ const zh = { dp_item7: "博弈型(仅列举题目)", dp_item8: "区间 DP", - dp_item8_text_comment: - "使用记忆化可能会更好书写,比如上面的 dp 代码改成记忆化递归就是:", dp_item8_keys1: ` 右边界倒序遍历,左边界正序遍历 `, diff --git a/src/roadmap/roadmap.jsx b/src/roadmap/roadmap.jsx index 9f9ef54..d091291 100644 --- a/src/roadmap/roadmap.jsx +++ b/src/roadmap/roadmap.jsx @@ -8,7 +8,8 @@ const dpSingleCode = ` dp = [0] * (n + 1) for i in range(1, n + 1): for j in range(i + 1, n + 1): - if 一定条件:dp[j] = 选择(dp[i], dp[j]) + # if 一定条件:dp[j] = 选择(dp[i], dp[j]) + if a certain condition is met: dp[j] = choose(dp[i], dp[j]). else: dp[i] = dp[i - 1] `; const dpDoubleCode = ` @@ -26,8 +27,10 @@ class Solution: def solve(self, s): n = len(s) dp = [[0] * n for _ in range(n)] + # 从右边界开始以逆向顺序遍历。 # Traverse in reverse order from the right boundary for i in range(n - 1, -1, -1): + # 从左边界开始以正向顺序遍历。 # Traverse in forward order from the left boundary for j in range(i + 1, n): # do something @@ -46,7 +49,7 @@ class Solution: return helper(0, len(s) - 1) `; -const roadmaps = { +const getRoadmaps = () => ({ "binary-search": { desc: t("Locale.learningRoute.binarySearchDesc"), items: [ @@ -96,6 +99,7 @@ def ability_test_bs(nums): l, r = 0, len(A) - 1 while l <= r: mid = (l + r) // 2 + # 唯一的区别在于这里和最左边的二分查找。 # The only difference is here and in the leftmost binary search. if possible(mid): l = mid + 1 else: r = mid - 1 @@ -186,6 +190,7 @@ def count_bs(nums, k): l, r = 0, len(A) - 1 while l <= r: mid = (l + r) // 2 + # 唯一的区别在于这里和最左边的二分查找。 # Only this is different from the leftmost binary if count_not_greater(mid) > k: r = mid - 1 else: l = mid + 1 @@ -339,9 +344,11 @@ def count_bs(nums, k): code: { language: "py", text: ` + # 一维 # one-dimensional for i in range(2, n): cur, prev = max(prev + nums[i], cur), cur + # 二维 # two-dimensional. def uniquePaths(self, m: int, n: int) -> int: dp = [1] * n @@ -502,9 +509,8 @@ def count_bs(nums, k): text: ` ${dpRangeCode} -# ${ - // 使用记忆化可能会更好书写,比如上面的 dp 代码改成记忆化递归就是: -t("Locale.learningRoute.dp_item8_text_comment")} +# 使用记忆化可能会更好书写,比如上面的 dp 代码改成记忆化递归就是: +# Using memoization might lead to better code writing. For example, the above DP code can be transformed into memoized recursion as: ${dpRangeCodeRecur}`, }, keys: [ @@ -539,10 +545,11 @@ ${dpRangeCodeRecur}`, }, ], }, -}; +}); export default function RoadMap() { const [topic, setTopic] = useState("dp"); + const roadmaps = getRoadmaps(); return ( <>