Merge branch 'master' of github.com:youngyangyang04/leetcode-master

This commit is contained in:
programmercarl
2024-07-15 16:49:26 +08:00
16 changed files with 752 additions and 52 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@ -152,6 +152,24 @@ public int[] twoSum(int[] nums, int target) {
return res;
}
```
```java
//使用哈希表方法2
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> indexMap = new HashMap<>();
for(int i = 0; i < nums.length; i++){
int balance = target - nums[i]; // 记录当前的目标值的余数
if(indexMap.containsKey(balance)){ // 查找当前的map中是否有满足要求的值
return new int []{i, indexMap.get(balance)}; // 如果有,返回目标值
} else{
indexMap.put(nums[i], i); // 如果没有把访问过的元素和下标加入map中
}
}
return null;
}
```
```java
//使用双指针
public int[] twoSum(int[] nums, int target) {

View File

@ -262,6 +262,11 @@ class Solution {
for (int j = i + 1; j < nums.length; j++) {
// nums[i]+nums[j] > target 直接返回, 剪枝操作
if (nums[i]+nums[j] > 0 && nums[i]+nums[j] > target) {
return result;
}
if (j > i + 1 && nums[j - 1] == nums[j]) { // 对nums[j]去重
continue;
}

View File

@ -287,6 +287,7 @@ function subsets(nums: number[]): number[][] {
### Rust
思路一:使用本题的标准解法,递归回溯。
```Rust
impl Solution {
fn backtracking(result: &mut Vec<Vec<i32>>, path: &mut Vec<i32>, nums: &Vec<i32>, start_index: usize) {
@ -308,6 +309,30 @@ impl Solution {
}
}
```
思路二使用二进制枚举n个元素的子集问题一共是$2^n$种情况。如果我们使用一个二进制数字每一位根据0和1来决定是选取该元素与否那么一共也是$2^n$的情况,正好可以一一对应,所以我们可以不使用递归,直接利用循环枚举完成子集问题。
这种方法的优点在于效率高,不需要递归调用,并且代码容易编写。缺点则是过滤某些非法情况时会比递归方法难写一点,不过在子集问题中不存在这个问题。
```Rust
impl Solution {
pub fn subsets(nums: Vec<i32>) -> Vec<Vec<i32>> {
let n = nums.len();
// 预分配2^n空间
let mut result = Vec::with_capacity(1 << n);
// 二进制枚举2^n种情况
for i in 0..(1 << n) {
let mut subset = Vec::new();
for j in 0..n {
// 枚举该二进制数字的每一位
// 如果该位是1对应位置上的元素加入子集否则跳过
if i & (1 << j) != 0 {
subset.push(nums[j]);
}
}
result.push(subset);
}
result
}
}
```
### C

View File

@ -265,7 +265,7 @@ func levelOrder(root *TreeNode) [][]int {
```go
/**
102. 二叉树的层序遍历
102. 二叉树的层序遍历 使用container包
*/
func levelOrder(root *TreeNode) [][]int {
res := [][]int{}
@ -296,6 +296,35 @@ func levelOrder(root *TreeNode) [][]int {
return res
}
/**
102. 二叉树的层序遍历 使用切片
*/
func levelOrder(root *TreeNode) [][]int {
res := make([][]int, 0)
if root == nil {
return res
}
queue := make([]*TreeNode, 0)
queue = append(queue, root)
for len(queue) > 0 {
size := len(queue)
level := make([]int, 0)
for i := 0; i < size; i++ {
node := queue[0]
queue = queue[1:]
level = append(level, node.Val)
if node.Left != nil {
queue = append(queue, node.Left)
}
if node.Right != nil {
queue = append(queue, node.Right)
}
}
res = append(res, level)
}
return res
}
/**
102. 二叉树的层序遍历:使用切片模拟队列,易理解
*/
@ -695,6 +724,41 @@ func levelOrderBottom(root *TreeNode) [][]int {
}
```
```GO
// 使用切片作为队列
func levelOrderBottom(root *TreeNode) [][]int {
res := make([][]int, 0)
if root == nil {
return res
}
queue := make([]*TreeNode, 0)
queue = append(queue, root)
for len(queue) > 0 {
size := len(queue)
level := make([]int, 0)
for i := 0; i < size; i++ {
node := queue[0]
queue = queue[1:]
level = append(level, node.Val)
if node.Left != nil {
queue = append(queue, node.Left)
}
if node.Right != nil {
queue = append(queue, node.Right)
}
}
res = append(res, level)
}
l, r := 0, len(res)-1
for l < r {
res[l], res[r] = res[r], res[l]
l++
r--
}
return res
}
```
#### Javascript:
```javascript
@ -1008,6 +1072,35 @@ func rightSideView(root *TreeNode) []int {
}
```
```GO
// 使用切片作为队列
func rightSideView(root *TreeNode) []int {
res := make([]int, 0)
if root == nil {
return res
}
queue := make([]*TreeNode, 0)
queue = append(queue, root)
for len(queue) > 0 {
size := len(queue)
for i := 0; i < size; i++ {
node := queue[0]
queue = queue[1:]
if node.Left != nil {
queue = append(queue, node.Left)
}
if node.Right != nil {
queue = append(queue, node.Right)
}
if i == size-1 {
res = append(res, node.Val)
}
}
}
return res
}
```
#### Javascript:
```javascript
@ -1299,6 +1392,35 @@ func averageOfLevels(root *TreeNode) []float64 {
}
```
```GO
// 使用切片作为队列
func averageOfLevels(root *TreeNode) []float64 {
res := make([]float64, 0)
if root == nil {
return res
}
queue := make([]*TreeNode, 0)
queue = append(queue, root)
for len(queue) > 0 {
size := len(queue)
sum := 0
for i := 0; i < size; i++ {
node := queue[0]
queue = queue[1:]
sum += node.Val
if node.Left != nil {
queue = append(queue, node.Left)
}
if node.Right != nil {
queue = append(queue, node.Right)
}
}
res = append(res, float64(sum)/float64(size))
}
return res
}
```
#### Javascript
```javascript
@ -1631,6 +1753,32 @@ func levelOrder(root *Node) [][]int {
}
```
```GO
// 使用切片作为队列
func levelOrder(root *Node) [][]int {
res := make([][]int, 0)
if root == nil {
return res
}
queue := make([]*Node, 0)
queue = append(queue, root)
for len(queue) > 0 {
size := len(queue)
level := make([]int, 0)
for i := 0; i < size; i++ {
node := queue[0]
queue = queue[1:]
level = append(level, node.Val)
if len(node.Children) > 0 {
queue = append(queue, node.Children...)
}
}
res = append(res, level)
}
return res
}
```
#### JavaScript
```JavaScript
@ -1930,6 +2078,37 @@ func max(x, y int) int {
}
```
```GO
// 使用切片作为队列
func largestValues(root *TreeNode) []int {
res := make([]int, 0)
if root == nil {
return res
}
queue := make([]*TreeNode, 0)
queue = append(queue, root)
for len(queue) > 0 {
size := len(queue)
maxValue := math.MinInt64
for i := 0; i < size; i++ {
node := queue[0]
queue = queue[1:]
if node.Val > maxValue {
maxValue = node.Val
}
if node.Left != nil {
queue = append(queue, node.Left)
}
if node.Right != nil {
queue = append(queue, node.Right)
}
}
res = append(res, maxValue)
}
return res
}
```
#### Javascript
```javascript
@ -2243,6 +2422,34 @@ func connect(root *Node) *Node {
```
```GO
// 使用切片作为队列
func connect(root *Node) *Node {
if root == nil {
return root
}
queue := make([]*Node, 0)
queue = append(queue, root)
for len(queue) > 0 {
size := len(queue)
for i := 0; i < size; i++ {
node := queue[i]
if i != size - 1 {
queue[i].Next = queue[i+1]
}
if node.Left != nil {
queue = append(queue, node.Left)
}
if node.Right != nil {
queue = append(queue, node.Right)
}
}
queue = queue[size:]
}
return root
}
```
#### JavaScript:
```javascript
@ -2531,6 +2738,34 @@ func connect(root *Node) *Node {
}
```
```GO
// 使用切片作为队列
func connect(root *Node) *Node {
if root == nil {
return root
}
queue := make([]*Node, 0)
queue = append(queue, root)
for len(queue) > 0 {
size := len(queue)
for i := 0; i < size; i++ {
node := queue[i]
if i != size - 1 {
queue[i].Next = queue[i+1]
}
if node.Left != nil {
queue = append(queue, node.Left)
}
if node.Right != nil {
queue = append(queue, node.Right)
}
}
queue = queue[size:]
}
return root
}
```
#### JavaScript:
```javascript
@ -2800,6 +3035,33 @@ func maxDepth(root *TreeNode) int {
}
```
```go
// 使用切片作为队列
func maxDepth(root *TreeNode) int {
if root == nil {
return 0
}
depth := 0
queue := make([]*TreeNode, 0)
queue = append(queue, root)
for len(queue) > 0 {
size := len(queue)
for i := 0; i < size; i++ {
node := queue[0]
queue = queue[1:]
if node.Left != nil {
queue = append(queue, node.Left)
}
if node.Right != nil {
queue = append(queue, node.Right)
}
}
depth++
}
return depth
}
```
#### JavaScript
```javascript
@ -3073,7 +3335,37 @@ func minDepth(root *TreeNode) int {
ans++//记录层数
}
return ans+1
return ans
}
```
```go
// 使用切片作为队列
func minDepth(root *TreeNode) int {
if root == nil {
return 0
}
depth := 0
queue := make([]*TreeNode, 0)
queue = append(queue, root)
for len(queue) > 0 {
size := len(queue)
depth++
for i := 0; i < size; i++ {
node := queue[0]
queue = queue[1:]
if node.Left != nil {
queue = append(queue, node.Left)
}
if node.Right != nil {
queue = append(queue, node.Right)
}
if node.Left == nil && node.Right == nil {
return depth
}
}
}
return depth
}
```

View File

@ -82,7 +82,7 @@
如动画所示:
![150.逆波兰表达式求值](https://code-thinking.cdn.bcebos.com/gifs/150.逆波兰表达式求值.gif)
相信看完动画大家应该知道,这和[1047. 删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)是差不的,只不过本题不要相邻元素做消除了,而是做运算!
相信看完动画大家应该知道,这和[1047. 删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)是差不的,只不过本题不要相邻元素做消除了,而是做运算!
C++代码如下:

View File

@ -224,9 +224,10 @@ struct ListNode* removeElements(struct ListNode* head, int val){
### Java
用原来的链表操作:
```java
/**
* 添加虚节点方式
* 方法1
* 时间复杂度 O(n)
* 空间复杂度 O(1)
* @param head
@ -234,25 +235,22 @@ struct ListNode* removeElements(struct ListNode* head, int val){
* @return
*/
public ListNode removeElements(ListNode head, int val) {
if (head == null) {
return head;
while(head!=null && head.val==val) {
head = head.next;
}
// 因为删除可能涉及到头节点所以设置dummy节点统一操作
ListNode dummy = new ListNode(-1, head);
ListNode pre = dummy;
ListNode cur = head;
while (cur != null) {
if (cur.val == val) {
pre.next = cur.next;
ListNode curr = head;
while(curr!=null && curr.next !=null) {
if(curr.next.val == val){
curr.next = curr.next.next;
} else {
pre = cur;
curr = curr.next;
}
cur = cur.next;
}
return dummy.next;
return head;
}
/**
* 不添加虚拟节点方式
* 方法1
* 时间复杂度 O(n)
* 空间复杂度 O(1)
* @param head
@ -280,8 +278,13 @@ public ListNode removeElements(ListNode head, int val) {
}
return head;
}
```
设置一个虚拟头结点:
```java
/**
* 不添加虚拟节点and pre Node方式
* 时间复杂度 O(n)
* 空间复杂度 O(1)
* @param head
@ -289,18 +292,21 @@ public ListNode removeElements(ListNode head, int val) {
* @return
*/
public ListNode removeElements(ListNode head, int val) {
while(head!=null && head.val==val){
head = head.next;
}
ListNode curr = head;
while(curr!=null){
while(curr.next!=null && curr.next.val == val){
curr.next = curr.next.next;
// 设置一个虚拟的头结点
ListNode dummy = new ListNode();
dummy.next = head;
ListNode cur = dummy;
while (cur.next != null) {
if (cur.next.val == val) {
cur.next = cur.next.next;
} else {
cur = cur.next;
}
curr = curr.next;
}
return head;
return dummy.next;
}
```
### Python

View File

@ -72,6 +72,7 @@ class MyStack {
public:
queue<int> que1;
queue<int> que2; // 辅助队列,用来备份
/** Initialize your data structure here. */
MyStack() {
@ -100,9 +101,28 @@ public:
return result;
}
/** Get the top element. */
int top() {
return que1.back();
/** Get the top element.
** Can not use back() direactly.
*/
int top(){
int size = que1.size();
size--;
while (size--){
// 将que1 导入que2但要留下最后一个元素
que2.push(que1.front());
que1.pop();
}
int result = que1.front(); // 留下的最后一个元素就是要回返的值
que2.push(que1.front()); // 获取值后将最后一个元素也加入que2中保持原本的结构不变
que1.pop();
que1 = que2; // 再将que2赋值给que1
while (!que2.empty()){
// 清空que2
que2.pop();
}
return result;
}
/** Returns whether the stack is empty. */
@ -126,14 +146,17 @@ C++优化代码
class MyStack {
public:
queue<int> que;
/** Initialize your data structure here. */
MyStack() {
}
/** Push element x onto stack. */
void push(int x) {
que.push(x);
}
/** Removes the element on top of the stack and returns that element. */
int pop() {
int size = que.size();
@ -147,9 +170,21 @@ public:
return result;
}
/** Get the top element. */
int top() {
return que.back();
/** Get the top element.
** Can not use back() direactly.
*/
int top(){
int size = que.size();
size--;
while (size--){
// 将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部
que.push(que.front());
que.pop();
}
int result = que.front(); // 此时获得的元素就是栈顶的元素了
que.push(que.front()); // 将获取完的元素也重新添加到队列尾部,保证数据结构没有变化
que.pop();
return result;
}
/** Returns whether the stack is empty. */

View File

@ -41,7 +41,7 @@
首先通过本题大家要明确什么是子序列,“子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序”。
本题也是代码随想录中子序列问题的第一题,如果没接触过这种题目的话,本题还是很难的,甚至想暴力去搜索也不知道怎么搜。
子序列问题是动态规划解决的经典问题当前下标i的递增子序列长度其实和i之前的下j的子序列长度有关系那又是什么样的关系呢。
子序列问题是动态规划解决的经典问题当前下标i的递增子序列长度其实和i之前的下j的子序列长度有关系那又是什么样的关系呢。
接下来,我们依然用动规五部曲来详细分析一波:

View File

@ -55,7 +55,7 @@ dp[i] 和 dp[i-1] dp[i + 1] 看上去都没啥关系。
我们在判断字符串S是否是回文那么如果我们知道 s[1]s[2]s[3] 这个子串是回文的,那么只需要比较 s[0]和s[4]这两个元素是否相同如果相同的话这个字符串s 就是回文串。
那么此时我们是不是能找到一种递归关系,也就是判断一个子字符串(字符串的下表范围[i,j])是否回文,依赖于,子字符串(下范围[i + 1, j - 1] 是否是回文。
那么此时我们是不是能找到一种递归关系,也就是判断一个子字符串(字符串下标范围[i,j])是否回文,依赖于,子字符串(下范围[i + 1, j - 1] 是否是回文。
所以为了明确这种递归关系我们的dp数组是要定义成一位二维dp数组。

View File

@ -328,14 +328,29 @@ class MyLinkedList {
return currentNode.val;
}
//在链表最前面插入一个节点等价于在第0个元素前添加
public void addAtHead(int val) {
addAtIndex(0, val);
ListNode newNode = new ListNode(val);
newNode.next = head.next;
head.next = newNode;
size++;
// 在链表最前面插入一个节点等价于在第0个元素前添加
// addAtIndex(0, val);
}
//在链表的最后插入一个节点,等价于在(末尾+1)个元素前添加
public void addAtTail(int val) {
addAtIndex(size, val);
ListNode newNode = new ListNode(val);
ListNode cur = head;
while (cur.next != null) {
cur = cur.next;
}
cur.next = newNode;
size++;
// 在链表的最后插入一个节点,等价于在(末尾+1)个元素前添加
// addAtIndex(size, val);
}
// 在第 index 个节点之前插入一个新节点例如index为0那么新插入的节点为链表的新头节点。
@ -365,10 +380,7 @@ class MyLinkedList {
return;
}
size--;
if (index == 0) {
head = head.next;
return;
}
//因为有虚拟头节点所以不用对Index=0的情况进行特殊处理
ListNode pred = head;
for (int i = 0; i < index ; i++) {
pred = pred.next;
@ -407,7 +419,7 @@ class MyLinkedList {
public int get(int index) {
//判断index是否有效
if(index<0 || index>=size){
if(index>=size){
return -1;
}
ListNode cur = this.head;
@ -441,10 +453,7 @@ class MyLinkedList {
if(index>size){
return;
}
//index小于0
if(index<0){
index = 0;
}
size++;
//找到前驱
ListNode pre = this.head;
@ -462,7 +471,7 @@ class MyLinkedList {
public void deleteAtIndex(int index) {
//判断索引是否有效
if(index<0 || index>=size){
if(index>=size){
return;
}
//删除操作

View File

@ -588,6 +588,40 @@ public class Main {
```
### Python
```python
# 接收输入
v, e = list(map(int, input().strip().split()))
# 按照常规的邻接矩阵存储图信息不可达的初始化为10001
graph = [[10001] * (v+1) for _ in range(v+1)]
for _ in range(e):
x, y, w = list(map(int, input().strip().split()))
graph[x][y] = w
graph[y][x] = w
# 定义加入生成树的标记数组和未加入生成树的最近距离
visited = [False] * (v + 1)
minDist = [10001] * (v + 1)
# 循环 n - 1 次,建立 n - 1 条边
# 从节点视角来看:每次选中一个节点加入树,更新剩余的节点到树的最短距离,
# 这一步其实蕴含了确定下一条选取的边,计入总路程 ans 的计算
for _ in range(1, v + 1):
min_val = 10002
cur = -1
for j in range(1, v + 1):
if visited[j] == False and minDist[j] < min_val:
cur = j
min_val = minDist[j]
visited[cur] = True
for j in range(1, v + 1):
if visited[j] == False and minDist[j] > graph[cur][j]:
minDist[j] = graph[cur][j]
ans = 0
for i in range(2, v + 1):
ans += minDist[i]
print(ans)
```
```python
def prim(v, e, edges):

View File

@ -422,9 +422,186 @@ int main() {
## 其他语言版本
### Java
#### 邻接矩阵写法
```java
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
static List<List<Integer>> result = new ArrayList<>(); // 收集符合条件的路径
static List<Integer> path = new ArrayList<>(); // 1节点到终点的路径
public static void dfs(int[][] graph, int x, int n) {
// 当前遍历的节点x 到达节点n
if (x == n) { // 找到符合条件的一条路径
result.add(new ArrayList<>(path));
return;
}
for (int i = 1; i <= n; i++) { // 遍历节点x链接的所有节点
if (graph[x][i] == 1) { // 找到 x链接的节点
path.add(i); // 遍历到的节点加入到路径中来
dfs(graph, i, n); // 进入下一层递归
path.remove(path.size() - 1); // 回溯,撤销本节点
}
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
// 节点编号从1到n所以申请 n+1 这么大的数组
int[][] graph = new int[n + 1][n + 1];
for (int i = 0; i < m; i++) {
int s = scanner.nextInt();
int t = scanner.nextInt();
// 使用邻接矩阵表示无向图1 表示 s 与 t 是相连的
graph[s][t] = 1;
}
path.add(1); // 无论什么路径已经是从1节点出发
dfs(graph, 1, n); // 开始遍历
// 输出结果
if (result.isEmpty()) System.out.println(-1);
for (List<Integer> pa : result) {
for (int i = 0; i < pa.size() - 1; i++) {
System.out.print(pa.get(i) + " ");
}
System.out.println(pa.get(pa.size() - 1));
}
}
}
```
#### 邻接表写法
```java
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
public class Main {
static List<List<Integer>> result = new ArrayList<>(); // 收集符合条件的路径
static List<Integer> path = new ArrayList<>(); // 1节点到终点的路径
public static void dfs(List<LinkedList<Integer>> graph, int x, int n) {
if (x == n) { // 找到符合条件的一条路径
result.add(new ArrayList<>(path));
return;
}
for (int i : graph.get(x)) { // 找到 x指向的节点
path.add(i); // 遍历到的节点加入到路径中来
dfs(graph, i, n); // 进入下一层递归
path.remove(path.size() - 1); // 回溯,撤销本节点
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
// 节点编号从1到n所以申请 n+1 这么大的数组
List<LinkedList<Integer>> graph = new ArrayList<>(n + 1);
for (int i = 0; i <= n; i++) {
graph.add(new LinkedList<>());
}
while (m-- > 0) {
int s = scanner.nextInt();
int t = scanner.nextInt();
// 使用邻接表表示 s -> t 是相连的
graph.get(s).add(t);
}
path.add(1); // 无论什么路径已经是从1节点出发
dfs(graph, 1, n); // 开始遍历
// 输出结果
if (result.isEmpty()) System.out.println(-1);
for (List<Integer> pa : result) {
for (int i = 0; i < pa.size() - 1; i++) {
System.out.print(pa.get(i) + " ");
}
System.out.println(pa.get(pa.size() - 1));
}
}
}
```
### Python
#### 邻接矩阵写法
``` python
def dfs(graph, x, n, path, result):
if x == n:
result.append(path.copy())
return
for i in range(1, n + 1):
if graph[x][i] == 1:
path.append(i)
dfs(graph, i, n, path, result)
path.pop()
def main():
n, m = map(int, input().split())
graph = [[0] * (n + 1) for _ in range(n + 1)]
for _ in range(m):
s, t = map(int, input().split())
graph[s][t] = 1
result = []
dfs(graph, 1, n, [1], result)
if not result:
print(-1)
else:
for path in result:
print(' '.join(map(str, path)))
if __name__ == "__main__":
main()
```
#### 邻接表写法
``` python
from collections import defaultdict
result = [] # 收集符合条件的路径
path = [] # 1节点到终点的路径
def dfs(graph, x, n):
if x == n: # 找到符合条件的一条路径
result.append(path.copy())
return
for i in graph[x]: # 找到 x指向的节点
path.append(i) # 遍历到的节点加入到路径中来
dfs(graph, i, n) # 进入下一层递归
path.pop() # 回溯,撤销本节点
def main():
n, m = map(int, input().split())
graph = defaultdict(list) # 邻接表
for _ in range(m):
s, t = map(int, input().split())
graph[s].append(t)
path.append(1) # 无论什么路径已经是从1节点出发
dfs(graph, 1, n) # 开始遍历
# 输出结果
if not result:
print(-1)
for pa in result:
print(' '.join(map(str, pa)))
if __name__ == "__main__":
main()
```
### Go
### Rust

View File

@ -167,7 +167,7 @@
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240510114004.png)
--------------
--------------
后面的过程一样的节点3 和 节点4入度都为0选哪个都行。
@ -344,8 +344,107 @@ int main() {
### Java
```java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
List<List<Integer>> umap = new ArrayList<>(); // 记录文件依赖关系
int[] inDegree = new int[n]; // 记录每个文件的入度
for (int i = 0; i < n; i++)
umap.add(new ArrayList<>());
for (int i = 0; i < m; i++) {
int s = scanner.nextInt();
int t = scanner.nextInt();
umap.get(s).add(t); // 记录s指向哪些文件
inDegree[t]++; // t的入度加一
}
Queue<Integer> queue = new LinkedList<>();
for (int i = 0; i < n; i++) {
if (inDegree[i] == 0) {
// 入度为0的文件可以作为开头先加入队列
queue.add(i);
}
}
List<Integer> result = new ArrayList<>();
// 拓扑排序
while (!queue.isEmpty()) {
int cur = queue.poll(); // 当前选中的文件
result.add(cur);
for (int file : umap.get(cur)) {
inDegree[file]--; // cur的指向的文件入度-1
if (inDegree[file] == 0) {
queue.add(file);
}
}
}
if (result.size() == n) {
for (int i = 0; i < result.size(); i++) {
System.out.print(result.get(i));
if (i < result.size() - 1) {
System.out.print(" ");
}
}
} else {
System.out.println(-1);
}
}
}
```
### Python
```python
from collections import deque, defaultdict
def topological_sort(n, edges):
inDegree = [0] * n # inDegree 记录每个文件的入度
umap = defaultdict(list) # 记录文件依赖关系
# 构建图和入度表
for s, t in edges:
inDegree[t] += 1
umap[s].append(t)
# 初始化队列加入所有入度为0的节点
queue = deque([i for i in range(n) if inDegree[i] == 0])
result = []
while queue:
cur = queue.popleft() # 当前选中的文件
result.append(cur)
for file in umap[cur]: # 获取该文件指向的文件
inDegree[file] -= 1 # cur的指向的文件入度-1
if inDegree[file] == 0:
queue.append(file)
if len(result) == n:
print(" ".join(map(str, result)))
else:
print(-1)
if __name__ == "__main__":
n, m = map(int, input().split())
edges = [tuple(map(int, input().split())) for _ in range(m)]
topological_sort(n, edges)
```
### Go
### Rust

View File

@ -25,7 +25,7 @@
index_{left}=(\sum_{i=0}^{i=k}2^i)+2*m-1-1=2^{k+1}+2m-3
$$
- 故左孩子的下为$index_{left}=index_{father}\times2+1$,同理可得到右子孩子的索引关系。也可以直接在左子孩子的基础上`+1`
- 故左孩子的下为$index_{left}=index_{father}\times2+1$,同理可得到右子孩子的索引关系。也可以直接在左子孩子的基础上`+1`

View File

@ -55,7 +55,7 @@
**构造二叉树有三个注意的点:**
* 分割时候,坚持区间不变量原则,左闭右开,或者左闭闭。
* 分割时候,坚持区间不变量原则,左闭右开,或者左闭闭。
* 分割的时候,注意后序 或者 前序已经有一个节点作为中间节点了,不能继续使用了。
* 如何使用切割后的后序数组来切合中序数组?利用中序数组大小一定是和后序数组的大小相同这一特点来进行切割。