diff --git a/107寻找存在的路径Java代码 b/107寻找存在的路径Java代码 deleted file mode 100644 index 7b83ca26..00000000 --- a/107寻找存在的路径Java代码 +++ /dev/null @@ -1,56 +0,0 @@ -JAVA: - -```Java - -import java.util.*; - -public class Main{ - public static void main(String[] args) { - int N, M; - Scanner scanner = new Scanner(System.in); - N = scanner.nextInt(); - M = scanner.nextInt(); - DisJoint disJoint = new DisJoint(N + 1); - for (int i = 0; i < M; ++i) { - disJoint.join(scanner.nextInt(), scanner.nextInt()); - } - if(disJoint.isSame(scanner.nextInt(), scanner.nextInt())) { - System.out.println("1"); - } else { - System.out.println("0"); - } - } - -} - -//并查集模板 -class DisJoint{ - private int[] father; - - public DisJoint(int N) { - father = new int[N]; - for (int i = 0; i < N; ++i){ - father[i] = i; - } - } - - public int find(int n) { - return n == father[n] ? n : (father[n] = find(father[n])); - } - - public void join (int n, int m) { - n = find(n); - m = find(m); - if (n == m) return; - father[m] = n; - } - - public boolean isSame(int n, int m){ - n = find(n); - m = find(m); - return n == m; - } - -} - -``` diff --git a/problems/0018.四数之和.md b/problems/0018.四数之和.md index 961de9ba..3e6e1a41 100644 --- a/problems/0018.四数之和.md +++ b/problems/0018.四数之和.md @@ -267,6 +267,7 @@ class Solution { break; } + if (j > i + 1 && nums[j - 1] == nums[j]) { // 对nums[j]去重 continue; } diff --git a/problems/0062.不同路径.md b/problems/0062.不同路径.md index b451704b..5b46caa9 100644 --- a/problems/0062.不同路径.md +++ b/problems/0062.不同路径.md @@ -371,6 +371,7 @@ class Solution: ``` ### Go +动态规划 ```Go func uniquePaths(m int, n int) int { dp := make([][]int, m) @@ -390,6 +391,26 @@ func uniquePaths(m int, n int) int { } ``` +数论方法 +```Go +func uniquePaths(m int, n int) int { + numerator := 1 + denominator := m - 1 + count := m - 1 + t := m + n - 2 + for count > 0 { + numerator *= t + t-- + for denominator != 0 && numerator % denominator == 0 { + numerator /= denominator + denominator-- + } + count-- + } + return numerator +} +``` + ### Javascript ```Javascript diff --git a/problems/0090.子集II.md b/problems/0090.子集II.md index 03bbd1dc..939ef369 100644 --- a/problems/0090.子集II.md +++ b/problems/0090.子集II.md @@ -310,6 +310,43 @@ class Solution: ``` ### Go +使用used数组 +```Go +var ( + result [][]int + path []int +) + +func subsetsWithDup(nums []int) [][]int { + result = make([][]int, 0) + path = make([]int, 0) + used := make([]bool, len(nums)) + sort.Ints(nums) // 去重需要排序 + backtracing(nums, 0, used) + return result +} + +func backtracing(nums []int, startIndex int, used []bool) { + tmp := make([]int, len(path)) + copy(tmp, path) + result = append(result, tmp) + for i := startIndex; i < len(nums); i++ { + // used[i - 1] == true,说明同一树枝candidates[i - 1]使用过 + // used[i - 1] == false,说明同一树层candidates[i - 1]使用过 + // 而我们要对同一树层使用过的元素进行跳过 + if i > 0 && nums[i] == nums[i-1] && used[i-1] == false { + continue + } + path = append(path, nums[i]) + used[i] = true + backtracing(nums, i + 1, used) + path = path[:len(path)-1] + used[i] = false + } +} +``` + +不使用used数组 ```Go var ( path []int diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md index 73d5e3c3..d1300a39 100644 --- a/problems/0093.复原IP地址.md +++ b/problems/0093.复原IP地址.md @@ -143,7 +143,7 @@ for (int i = startIndex; i < s.size(); i++) { 代码如下: ```CPP -// 判断字符串s在左闭又闭区间[start, end]所组成的数字是否合法 +// 判断字符串s在左闭右闭区间[start, end]所组成的数字是否合法 bool isValid(const string& s, int start, int end) { if (start > end) { return false; @@ -208,7 +208,7 @@ private: } else break; // 不合法,直接结束本层循环 } } - // 判断字符串s在左闭又闭区间[start, end]所组成的数字是否合法 + // 判断字符串s在左闭右闭区间[start, end]所组成的数字是否合法 bool isValid(const string& s, int start, int end) { if (start > end) { return false; diff --git a/problems/0110.平衡二叉树.md b/problems/0110.平衡二叉树.md index dd05bdd6..f8071333 100644 --- a/problems/0110.平衡二叉树.md +++ b/problems/0110.平衡二叉树.md @@ -623,6 +623,8 @@ class Solution: ``` ### Go: +递归法 + ```Go func isBalanced(root *TreeNode) bool { h := getHeight(root) @@ -653,6 +655,64 @@ func max(a, b int) int { } ``` +迭代法 + +```Go +func isBalanced(root *TreeNode) bool { + st := make([]*TreeNode, 0) + if root == nil { + return true + } + st = append(st, root) + for len(st) > 0 { + node := st[len(st)-1] + st = st[:len(st)-1] + if math.Abs(float64(getDepth(node.Left)) - float64(getDepth(node.Right))) > 1 { + return false + } + if node.Right != nil { + st = append(st, node.Right) + } + if node.Left != nil { + st = append(st, node.Left) + } + } + return true +} + +func getDepth(cur *TreeNode) int { + st := make([]*TreeNode, 0) + if cur != nil { + st = append(st, cur) + } + depth := 0 + result := 0 + for len(st) > 0 { + node := st[len(st)-1] + if node != nil { + st = st[:len(st)-1] + st = append(st, node, nil) + depth++ + if node.Right != nil { + st = append(st, node.Right) + } + if node.Left != nil { + st = append(st, node.Left) + } + } else { + st = st[:len(st)-1] + node = st[len(st)-1] + st = st[:len(st)-1] + depth-- + } + if result < depth { + result = depth + } + } + return result +} +``` + ### JavaScript: 递归法: diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index 2beb8a7f..6709a2fb 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -727,6 +727,48 @@ class Solution: ```go //递归法 +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func hasPathSum(root *TreeNode, targetSum int) bool { + if root == nil { + return false + } + return traversal(root, targetSum - root.Val) +} + +func traversal(cur *TreeNode, count int) bool { + if cur.Left == nil && cur.Right == nil && count == 0 { + return true + } + if cur.Left == nil && cur.Right == nil { + return false + } + if cur.Left != nil { + count -= cur.Left.Val + if traversal(cur.Left, count) { + return true + } + count += cur.Left.Val + } + if cur.Right != nil { + count -= cur.Right.Val + if traversal(cur.Right, count) { + return true + } + count += cur.Right.Val + } + return false +} +``` + +```go +//递归法精简 /** * Definition for a binary tree node. * type TreeNode struct { diff --git a/problems/0131.分割回文串.md b/problems/0131.分割回文串.md index 4a868651..4eca0ddf 100644 --- a/problems/0131.分割回文串.md +++ b/problems/0131.分割回文串.md @@ -527,6 +527,7 @@ class Solution: ``` ### Go +回溯 基本版 ```go var ( path []string // 放已经回文的子串 @@ -565,6 +566,63 @@ func isPalindrome(s string) bool { } ``` +回溯+动态规划优化回文串判断 +```go +var ( + result [][]string + path []string // 放已经回文的子串 + isPalindrome [][]bool // 放事先计算好的是否回文子串的结果 +) + +func partition(s string) [][]string { + result = make([][]string, 0) + path = make([]string, 0) + computePalindrome(s) + backtracing(s, 0) + return result +} + +func backtracing(s string, startIndex int) { + // 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了 + if startIndex >= len(s) { + tmp := make([]string, len(path)) + copy(tmp, path) + result = append(result, tmp) + return + } + for i := startIndex; i < len(s); i++ { + if isPalindrome[startIndex][i] { // 是回文子串 + // 获取[startIndex,i]在s中的子串 + path = append(path, s[startIndex:i+1]) + } else { // 不是回文,跳过 + continue + } + backtracing(s, i + 1) // 寻找i+1为起始位置的子串 + path = path[:len(path)-1] // 回溯过程,弹出本次已经添加的子串 + } +} + +func computePalindrome(s string) { + // isPalindrome[i][j] 代表 s[i:j](双边包括)是否是回文字串 + isPalindrome = make([][]bool, len(s)) + for i := 0; i < len(isPalindrome); i++ { + isPalindrome[i] = make([]bool, len(s)) + } + for i := len(s)-1; i >= 0; i-- { + // 需要倒序计算, 保证在i行时, i+1行已经计算好了 + for j := i; j < len(s); j++ { + if j == i { + isPalindrome[i][j] = true + } else if j - i == 1 { + isPalindrome[i][j] = s[i] == s[j] + } else { + isPalindrome[i][j] = s[i] == s[j] && isPalindrome[i+1][j-1] + } + } + } +} +``` + ### JavaScript ```js diff --git a/problems/0203.移除链表元素.md b/problems/0203.移除链表元素.md index 64124fbb..f6b5ef6d 100644 --- a/problems/0203.移除链表元素.md +++ b/problems/0203.移除链表元素.md @@ -149,7 +149,35 @@ public: * 时间复杂度: O(n) * 空间复杂度: O(1) +**也可以通过递归的思路解决本题:** +基础情况:对于空链表,不需要移除元素。 + +递归情况:首先检查头节点的值是否为 val,如果是则移除头节点,答案即为在头节点的后续节点上递归的结果;如果头节点的值不为 val,则答案为头节点与在头节点的后续节点上递归得到的新链表拼接的结果。 + +```CPP +class Solution { +public: + ListNode* removeElements(ListNode* head, int val) { + // 基础情况:空链表 + if (head == nullptr) { + return nullptr; + } + + // 递归处理 + if (head->val == val) { + ListNode* newHead = removeElements(head->next, val); + delete head; + return newHead; + } else { + head->next = removeElements(head->next, val); + return head; + } + } +}; +``` +* 时间复杂度:O(n) +* 空间复杂度:O(n) ## 其他语言版本 diff --git a/problems/0226.翻转二叉树.md b/problems/0226.翻转二叉树.md index 824968f0..e501b298 100644 --- a/problems/0226.翻转二叉树.md +++ b/problems/0226.翻转二叉树.md @@ -14,7 +14,7 @@ ![226.翻转二叉树](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203192644329.png) -这道题目背后有一个让程序员心酸的故事,听说 Homebrew的作者Max Howell,就是因为没在白板上写出翻转二叉树,最后被Google拒绝了。(真假不做判断,权当一个乐子哈) +这道题目背后有一个让程序员心酸的故事,听说 Homebrew的作者Max Howell,就是因为没在白板上写出翻转二叉树,最后被Google拒绝了。(真假不做判断,全当一个乐子哈) ## 算法公开课 @@ -1033,3 +1033,4 @@ public TreeNode InvertTree(TreeNode root) { + diff --git a/problems/0404.左叶子之和.md b/problems/0404.左叶子之和.md index 1ba71dc9..66aff68f 100644 --- a/problems/0404.左叶子之和.md +++ b/problems/0404.左叶子之和.md @@ -337,6 +337,21 @@ func sumOfLeftLeaves(root *TreeNode) int { } ``` +**递归精简版** + +```go +func sumOfLeftLeaves(root *TreeNode) int { + if root == nil { + return 0 + } + leftValue := 0 + if root.Left != nil && root.Left.Left == nil && root.Left.Right == nil { + leftValue = root.Left.Val + } + return leftValue + sumOfLeftLeaves(root.Left) + sumOfLeftLeaves(root.Right) +} +``` + **迭代法(前序遍历)** ```go diff --git a/problems/0707.设计链表.md b/problems/0707.设计链表.md index 141156cf..0cb2f2f2 100644 --- a/problems/0707.设计链表.md +++ b/problems/0707.设计链表.md @@ -165,6 +165,140 @@ private: ## 其他语言版本 +### C++双链表法: + +```CPP +//采用循环虚拟结点的双链表实现 +class MyLinkedList { +public: + // 定义双向链表节点结构体 + struct DList { + int elem; // 节点存储的元素 + DList *next; // 指向下一个节点的指针 + DList *prev; // 指向上一个节点的指针 + // 构造函数,创建一个值为elem的新节点 + DList(int elem) : elem(elem), next(nullptr), prev(nullptr) {}; + }; + + // 构造函数,初始化链表 + MyLinkedList() { + sentinelNode = new DList(0); // 创建哨兵节点,不存储有效数据 + sentinelNode->next = sentinelNode; // 哨兵节点的下一个节点指向自身,形成循环 + sentinelNode->prev = sentinelNode; // 哨兵节点的上一个节点指向自身,形成循环 + size = 0; // 初始化链表大小为0 + } + + // 获取链表中第index个节点的值 + int get(int index) { + if (index > (size - 1) || index < 0) { // 检查索引是否超出范围 + return -1; // 如果超出范围,返回-1 + } + int num; + int mid = size >> 1; // 计算链表中部位置 + DList *curNode = sentinelNode; // 从哨兵节点开始 + if (index < mid) { // 如果索引小于中部位置,从前往后遍历 + for (int i = 0; i < index + 1; i++) { + curNode = curNode->next; // 移动到目标节点 + } + } else { // 如果索引大于等于中部位置,从后往前遍历 + for (int i = 0; i < size - index; i++) { + curNode = curNode->prev; // 移动到目标节点 + } + } + num = curNode->elem; // 获取目标节点的值 + return num; // 返回节点的值 + } + + // 在链表头部添加节点 + void addAtHead(int val) { + DList *newNode = new DList(val); // 创建新节点 + DList *next = sentinelNode->next; // 获取当前头节点的下一个节点 + newNode->prev = sentinelNode; // 新节点的上一个节点指向哨兵节点 + newNode->next = next; // 新节点的下一个节点指向原来的头节点 + size++; // 链表大小加1 + sentinelNode->next = newNode; // 哨兵节点的下一个节点指向新节点 + next->prev = newNode; // 原来的头节点的上一个节点指向新节点 + } + + // 在链表尾部添加节点 + void addAtTail(int val) { + DList *newNode = new DList(val); // 创建新节点 + DList *prev = sentinelNode->prev; // 获取当前尾节点的上一个节点 + newNode->next = sentinelNode; // 新节点的下一个节点指向哨兵节点 + newNode->prev = prev; // 新节点的上一个节点指向原来的尾节点 + size++; // 链表大小加1 + sentinelNode->prev = newNode; // 哨兵节点的上一个节点指向新节点 + prev->next = newNode; // 原来的尾节点的下一个节点指向新节点 + } + + // 在链表中的第index个节点之前添加值为val的节点 + void addAtIndex(int index, int val) { + if (index > size) { // 检查索引是否超出范围 + return; // 如果超出范围,直接返回 + } + if (index <= 0) { // 如果索引为0或负数,在头部添加节点 + addAtHead(val); + return; + } + int num; + int mid = size >> 1; // 计算链表中部位置 + DList *curNode = sentinelNode; // 从哨兵节点开始 + if (index < mid) { // 如果索引小于中部位置,从前往后遍历 + for (int i = 0; i < index; i++) { + curNode = curNode->next; // 移动到目标位置的前一个节点 + } + DList *temp = curNode->next; // 获取目标位置的节点 + DList *newNode = new DList(val); // 创建新节点 + curNode->next = newNode; // 在目标位置前添加新节点 + temp->prev = newNode; // 目标位置的节点的前一个节点指向新节点 + newNode->next = temp; // 新节点的下一个节点指向目标位置的结点 + newNode->prev = curNode; // 新节点的上一个节点指向当前节点 + } else { // 如果索引大于等于中部位置,从后往前遍历 + for (int i = 0; i < size - index; i++) { + curNode = curNode->prev; // 移动到目标位置的后一个节点 + } + DList *temp = curNode->prev; // 获取目标位置的节点 + DList *newNode = new DList(val); // 创建新节点 + curNode->prev = newNode; // 在目标位置后添加新节点 + temp->next = newNode; // 目标位置的节点的下一个节点指向新节点 + newNode->prev = temp; // 新节点的上一个节点指向目标位置的节点 + newNode->next = curNode; // 新节点的下一个节点指向当前节点 + } + size++; // 链表大小加1 + } + + // 删除链表中的第index个节点 + void deleteAtIndex(int index) { + if (index > (size - 1) || index < 0) { // 检查索引是否超出范围 + return; // 如果超出范围,直接返回 + } + int num; + int mid = size >> 1; // 计算链表中部位置 + DList *curNode = sentinelNode; // 从哨兵节点开始 + if (index < mid) { // 如果索引小于中部位置,从前往后遍历 + for (int i = 0; i < index; i++) { + curNode = curNode->next; // 移动到目标位置的前一个节点 + } + DList *next = curNode->next->next; // 获取目标位置的下一个节点 + curNode->next = next; // 删除目标位置的节点 + next->prev = curNode; // 目标位置的下一个节点的前一个节点指向当前节点 + } else { // 如果索引大于等于中部位置,从后往前遍历 + for (int i = 0; i < size - index - 1; i++) { + curNode = curNode->prev; // 移动到目标位置的后一个节点 + } + DList *prev = curNode->prev->prev; // 获取目标位置的下一个节点 + curNode->prev = prev; // 删除目标位置的节点 + prev->next = curNode; // 目标位置的下一个节点的下一个节点指向当前节点 + } + size--; // 链表大小减1 + } + +private: + int size; // 链表的大小 + DList *sentinelNode; // 哨兵节点的指针 +}; +``` + ### C: ```C diff --git a/problems/0977.有序数组的平方.md b/problems/0977.有序数组的平方.md index b10620d0..7119dda5 100644 --- a/problems/0977.有序数组的平方.md +++ b/problems/0977.有序数组的平方.md @@ -100,6 +100,18 @@ public: ## 其他语言版本 ### Java: +排序法 +```Java +class Solution { + public int[] sortedSquares(int[] nums) { + for (int i = 0; i < nums.length; i++) { + nums[i] = nums[i] * nums[i]; + } + Arrays.sort(nums); + return nums; + } +} +``` ```Java class Solution { diff --git a/problems/kamacoder/0104.建造最大岛屿.md b/problems/kamacoder/0104.建造最大岛屿.md index 7d67b7fc..7132217b 100644 --- a/problems/kamacoder/0104.建造最大岛屿.md +++ b/problems/kamacoder/0104.建造最大岛屿.md @@ -366,6 +366,79 @@ public class Main { ### Python +```Python +import collections + +directions = [[-1, 0], [0, 1], [0, -1], [1, 0]] +area = 0 + +def dfs(i, j, grid, visited, num): + global area + + if visited[i][j]: + return + + visited[i][j] = True + grid[i][j] = num # 标记岛屿号码 + area += 1 + + for x, y in directions: + new_x = i + x + new_y = j + y + if ( + 0 <= new_x < len(grid) + and 0 <= new_y < len(grid[0]) + and grid[new_x][new_y] == "1" + ): + dfs(new_x, new_y, grid, visited, num) + + +def main(): + global area + + N, M = map(int, input().strip().split()) + grid = [] + for i in range(N): + grid.append(input().strip().split()) + visited = [[False] * M for _ in range(N)] + rec = collections.defaultdict(int) + + cnt = 2 + for i in range(N): + for j in range(M): + if grid[i][j] == "1": + area = 0 + dfs(i, j, grid, visited, cnt) + rec[cnt] = area # 纪录岛屿面积 + cnt += 1 + + res = 0 + for i in range(N): + for j in range(M): + if grid[i][j] == "0": + max_island = 1 # 将水变为陆地,故从1开始计数 + v = set() + for x, y in directions: + new_x = i + x + new_y = j + y + if ( + 0 <= new_x < len(grid) + and 0 <= new_y < len(grid[0]) + and grid[new_x][new_y] != "0" + and grid[new_x][new_y] not in v # 岛屿不可重复 + ): + max_island += rec[grid[new_x][new_y]] + v.add(grid[new_x][new_y]) + res = max(res, max_island) + + if res == 0: + return max(rec.values()) # 无水的情况 + return res + +if __name__ == "__main__": + print(main()) +``` + ### Go ### Rust diff --git a/problems/kamacoder/0107.寻找存在的路径.md b/problems/kamacoder/0107.寻找存在的路径.md index 906609c9..70339a9d 100644 --- a/problems/kamacoder/0107.寻找存在的路径.md +++ b/problems/kamacoder/0107.寻找存在的路径.md @@ -158,7 +158,62 @@ int main() { ## 其他语言版本 -### Java +### Java + +```Java + +import java.util.*; + +public class Main{ + public static void main(String[] args) { + int N, M; + Scanner scanner = new Scanner(System.in); + N = scanner.nextInt(); + M = scanner.nextInt(); + DisJoint disJoint = new DisJoint(N + 1); + for (int i = 0; i < M; ++i) { + disJoint.join(scanner.nextInt(), scanner.nextInt()); + } + if(disJoint.isSame(scanner.nextInt(), scanner.nextInt())) { + System.out.println("1"); + } else { + System.out.println("0"); + } + } + +} + +//并查集模板 +class DisJoint{ + private int[] father; + + public DisJoint(int N) { + father = new int[N]; + for (int i = 0; i < N; ++i){ + father[i] = i; + } + } + + public int find(int n) { + return n == father[n] ? n : (father[n] = find(father[n])); + } + + public void join (int n, int m) { + n = find(n); + m = find(m); + if (n == m) return; + father[m] = n; + } + + public boolean isSame(int n, int m){ + n = find(n); + m = find(m); + return n == m; + } + +} + +``` ### Python diff --git a/problems/kamacoder/0108.冗余连接.md b/problems/kamacoder/0108.冗余连接.md index 70884139..8acb2f10 100644 --- a/problems/kamacoder/0108.冗余连接.md +++ b/problems/kamacoder/0108.冗余连接.md @@ -141,6 +141,70 @@ int main() { ### Javascript +```javascript +const r1 = require('readline').createInterface({ input: process.stdin }); +// 创建readline接口 +let iter = r1[Symbol.asyncIterator](); +// 创建异步迭代器 +const readline = async () => (await iter.next()).value; + + +let N // 节点数和边数 +let father = [] // 并查集 + + +// 并查集初始化 +const init = () => { + for (let i = 1; i <= N; i++) father[i] = i; +} + +// 并查集里寻根的过程 +const find = (u) => { + return u == father[u] ? u : father[u] = find(father[u]) +} + +// 将v->u 这条边加入并查集 +const join = (u, v) => { + u = find(u) + v = find(v) + if (u == v) return // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回 + father[v] = u +} + +// 判断 u 和 v是否找到同一个根 +const isSame = (u, v) => { + u = find(u) + v = find(v) + return u == v +} + + +(async function () { + // 读取第一行输入 + let line = await readline(); + N = Number(line); + + // 初始化并查集 + father = new Array(N) + init() + + // 读取边信息, 加入并查集 + for (let i = 0; i < N; i++) { + line = await readline() + line = line.split(' ').map(Number) + + if (!isSame(line[0], line[1])) { + join(line[0], line[1]) + }else{ + console.log(line[0], line[1]); + break + } + } +})() +``` + + + ### TypeScript ### PhP diff --git a/problems/kamacoder/0110.字符串接龙.md b/problems/kamacoder/0110.字符串接龙.md index feeec6dd..5d13e368 100644 --- a/problems/kamacoder/0110.字符串接龙.md +++ b/problems/kamacoder/0110.字符串接龙.md @@ -217,6 +217,38 @@ public class Main { ``` ### Python +```Python +def judge(s1,s2): + count=0 + for i in range(len(s1)): + if s1[i]!=s2[i]: + count+=1 + return count==1 + +if __name__=='__main__': + n=int(input()) + beginstr,endstr=map(str,input().split()) + if beginstr==endstr: + print(0) + exit() + strlist=[] + for i in range(n): + strlist.append(input()) + + # use bfs + visit=[False for i in range(n)] + queue=[[beginstr,1]] + while queue: + str,step=queue.pop(0) + if judge(str,endstr): + print(step+1) + exit() + for i in range(n): + if visit[i]==False and judge(strlist[i],str): + visit[i]=True + queue.append([strlist[i],step+1]) + print(0) +``` ### Go diff --git a/problems/kamacoder/0117.软件构建.md b/problems/kamacoder/0117.软件构建.md index 05cb7358..bb0c9aec 100644 --- a/problems/kamacoder/0117.软件构建.md +++ b/problems/kamacoder/0117.软件构建.md @@ -193,7 +193,7 @@ 理解思想后,确实不难,但代码写起来也不容易。 -为了每次可以找到所有节点的入度信息,我们要在初始话的时候,就把每个节点的入度 和 每个节点的依赖关系做统计。 +为了每次可以找到所有节点的入度信息,我们要在初始化的时候,就把每个节点的入度 和 每个节点的依赖关系做统计。 代码如下: @@ -451,6 +451,80 @@ if __name__ == "__main__": ### Javascript +```javascript +const r1 = require('readline').createInterface({ input: process.stdin }); +// 创建readline接口 +let iter = r1[Symbol.asyncIterator](); +// 创建异步迭代器 +const readline = async () => (await iter.next()).value; + + +let N, M // 节点数和边数 +let inDegrees = [] // 入度 +let umap = new Map() // 记录文件依赖关系 +let result = [] // 结果 + + +// 根据输入, 初始化数据 +const init = async () => { + // 读取第一行输入 + let line = await readline(); + [N, M] = line.split(' ').map(Number) + + inDegrees = new Array(N).fill(0) + + // 读取边集 + while (M--) { + line = await readline(); + let [x, y] = line.split(' ').map(Number) + + // 记录入度 + inDegrees[y]++ + + // 记录x指向哪些文件 + if (!umap.has(x)) { + umap.set(x, [y]) + } else { + umap.get(x).push(y) + } + } +} + +(async function () { + // 根据输入, 初始化数据 + await init() + + let queue = [] // 入度为0的节点 + for (let i = 0; i < N; i++) { + if (inDegrees[i] == 0) { + queue.push(i) + } + } + + while (queue.length) { + let cur = queue.shift() //当前文件 + + result.push(cur) + + let files = umap.get(cur) // 当前文件指向的文件 + + // 当前文件指向的文件入度减1 + if (files && files.length) { + for (let i = 0; i < files.length; i++) { + inDegrees[files[i]]-- + if (inDegrees[files[i]] == 0) queue.push(files[i]) + } + } + } + + // 这里result.length == N 一定要判断, 因为可能存在环 + if (result.length == N) return console.log(result.join(' ')) + console.log(-1) +})() +``` + + + ### TypeScript ### PhP diff --git a/problems/背包理论基础01背包-1.md b/problems/背包理论基础01背包-1.md index 0c78e3f6..2e1cd52c 100644 --- a/problems/背包理论基础01背包-1.md +++ b/problems/背包理论基础01背包-1.md @@ -193,7 +193,7 @@ dp[0][j],即:i为0,存放编号0的物品的时候,各个容量的背包 代码初始化如下: -``` +```CPP for (int j = 0 ; j < weight[0]; j++) { // 当然这一步,如果把dp数组预先初始化为0了,这一步就可以省略,但很多同学应该没有想清楚这一点。 dp[0][j] = 0; }