This commit is contained in:
programmercarl
2024-10-09 16:59:26 +08:00
21 changed files with 753 additions and 10 deletions

View File

@ -214,6 +214,7 @@ class Solution:
return result return result
``` ```
贪心法
```python ```python
class Solution: class Solution:
def maxSubArray(self, nums): def maxSubArray(self, nums):
@ -226,8 +227,18 @@ class Solution:
if count <= 0: # 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和 if count <= 0: # 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和
count = 0 count = 0
return result return result
```
动态规划
```python
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
dp = [0] * len(nums)
dp[0] = nums[0]
res = nums[0]
for i in range(1, len(nums)):
dp[i] = max(dp[i-1] + nums[i], nums[i])
res = max(res, dp[i])
return res
``` ```
### Go ### Go
贪心法 贪心法

View File

@ -184,6 +184,16 @@ if __name__ == '__main__':
### Go ### Go
```go ```go
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func climbStairs(n int, m int) int { func climbStairs(n int, m int) int {
dp := make([]int, n+1) dp := make([]int, n+1)
dp[0] = 1 dp[0] = 1

View File

@ -467,9 +467,37 @@ class Solution:
num = int(s[start:end+1]) num = int(s[start:end+1])
return 0 <= num <= 255 return 0 <= num <= 255
回溯版本三
```python
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
result = []
self.backtracking(s, 0, [], result)
return result
def backtracking(self, s, startIndex, path, result):
if startIndex == len(s):
result.append('.'.join(path[:]))
return
for i in range(startIndex, min(startIndex+3, len(s))):
# 如果 i 往后遍历了,并且当前地址的第一个元素是 0 ,就直接退出
if i > startIndex and s[startIndex] == '0':
break
# 比如 s 长度为 5当前遍历到 i = 3 这个元素
# 因为还没有执行任何操作,所以此时剩下的元素数量就是 5 - 3 = 2 ,即包括当前的 i 本身
# path 里面是当前包含的子串,所以有几个元素就表示储存了几个地址
# 所以 (4 - len(path)) * 3 表示当前路径至多能存放的元素个数
# 4 - len(path) 表示至少要存放的元素个数
if (4 - len(path)) * 3 < len(s) - i or 4 - len(path) > len(s) - i:
break
if i - startIndex == 2:
if not int(s[startIndex:i+1]) <= 255:
break
path.append(s[startIndex:i+1])
self.backtracking(s, i+1, path, result)
path.pop()
``` ```
### Go ### Go

View File

@ -609,10 +609,13 @@ class Solution:
while stack: while stack:
node = stack.pop() node = stack.pop()
if node: if node:
stack.append(node) stack.append(node) # 中
stack.append(None) stack.append(None)
if node.left: stack.append(node.left) # 采用数组进行迭代,先将右节点加入,保证左节点能够先出栈
if node.right: stack.append(node.right) if node.right: # 右
stack.append(node.right)
if node.left: # 左
stack.append(node.left)
else: else:
real_node = stack.pop() real_node = stack.pop()
left, right = height_map.get(real_node.left, 0), height_map.get(real_node.right, 0) left, right = height_map.get(real_node.left, 0), height_map.get(real_node.right, 0)

View File

@ -158,7 +158,7 @@ i从0开始累加rest[i]和记为curSum一旦curSum小于零说明[0, i
如果 curSum<0 说明 区间和1 + 区间和2 < 0 那么 假设从上图中的位置开始计数curSum不会小于0的话就是 区间和2>0。 如果 curSum<0 说明 区间和1 + 区间和2 < 0 那么 假设从上图中的位置开始计数curSum不会小于0的话就是 区间和2>0。
区间和1 + 区间和2 < 0 同时 区间和2>0只能说明区间和1 < 0 那么就会从假设的箭头初就开始从新选择其实位置了 区间和1 + 区间和2 < 0 同时 区间和2>0只能说明区间和1 < 0 那么就会从假设的箭头初就开始从新选择起始位置了
**那么局部最优当前累加rest[i]的和curSum一旦小于0起始位置至少要是i+1因为从i之前开始一定不行。全局最优找到可以跑一圈的起始位置** **那么局部最优当前累加rest[i]的和curSum一旦小于0起始位置至少要是i+1因为从i之前开始一定不行。全局最优找到可以跑一圈的起始位置**

View File

@ -475,7 +475,45 @@ class Solution:
words = words[::-1] # 反转单词 words = words[::-1] # 反转单词
return ' '.join(words) #列表转换成字符串 return ' '.join(words) #列表转换成字符串
``` ```
(版本四) 将字符串转换为列表后,使用双指针去除空格
```python
class Solution:
def single_reverse(self, s, start: int, end: int):
while start < end:
s[start], s[end] = s[end], s[start]
start += 1
end -= 1
def reverseWords(self, s: str) -> str:
result = ""
fast = 0
# 1. 首先将原字符串反转并且除掉空格, 并且加入到新的字符串当中
# 由于Python字符串的不可变性因此只能转换为列表进行处理
s = list(s)
s.reverse()
while fast < len(s):
if s[fast] != " ":
if len(result) != 0:
result += " "
while s[fast] != " " and fast < len(s):
result += s[fast]
fast += 1
else:
fast += 1
# 2.其次将每个单词进行翻转操作
slow = 0
fast = 0
result = list(result)
while fast <= len(result):
if fast == len(result) or result[fast] == " ":
self.single_reverse(result, slow, fast - 1)
slow = fast + 1
fast += 1
else:
fast += 1
return "".join(result)
```
### Go ### Go
版本一: 版本一:

View File

@ -454,7 +454,11 @@ impl Solution {
p: Option<Rc<RefCell<TreeNode>>>, p: Option<Rc<RefCell<TreeNode>>>,
q: Option<Rc<RefCell<TreeNode>>>, q: Option<Rc<RefCell<TreeNode>>>,
) -> Option<Rc<RefCell<TreeNode>>> { ) -> Option<Rc<RefCell<TreeNode>>> {
if root == p || root == q || root.is_none() { if root.is_none() {
return root;
}
if Rc::ptr_eq(root.as_ref().unwrap(), p.as_ref().unwrap())
|| Rc::ptr_eq(root.as_ref().unwrap(), q.as_ref().unwrap()) {
return root; return root;
} }
let left = Self::lowest_common_ancestor( let left = Self::lowest_common_ancestor(

View File

@ -337,6 +337,29 @@ pub fn length_of_lis(nums: Vec<i32>) -> i32 {
} }
``` ```
### Cangjie:
```cangjie
func lengthOfLIS(nums: Array<Int64>): Int64 {
let n = nums.size
if (n <= 1) {
return n
}
let dp = Array(n, item: 1)
var res = 0
for (i in 1..n) {
for (j in 0..i) {
if (nums[i] > nums[j]) {
dp[i] = max(dp[i], dp[j] + 1)
}
}
res = max(dp[i], res)
}
return res
}
```
<p align="center"> <p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank"> <a href="https://programmercarl.com/other/kstar.html" target="_blank">

View File

@ -243,6 +243,29 @@ class Solution {
} }
} }
``` ```
贪心
```Java
class Solution {
public int integerBreak(int n) {
// with 贪心
// 通过数学原理拆出更多的3乘积越大
/**
@Param: an int, the integer we need to break.
@Return: an int, the maximum integer after breaking
@Method: Using math principle to solve this problem
@Time complexity: O(1)
**/
if(n == 2) return 1;
if(n == 3) return 2;
int result = 1;
while(n > 4) {
n-=3;
result *=3;
}
return result*n;
}
}
```
### Python ### Python
动态规划版本一 动态规划版本一

View File

@ -177,7 +177,7 @@ KMP算法中next数组为什么遇到字符不匹配的时候可以找到上一
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240913110841.png) ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240913110841.png)
这里有录友就想如果字符串s 是有是有最小重复子串p组成最长相等前后缀就不能更长一些 例如这样: 这里有录友就想如果字符串s 是最小重复子串p组成最长相等前后缀就不能更长一些 例如这样:
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240913114348.png) ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240913114348.png)
@ -884,3 +884,4 @@ public int[] GetNext(string s)
<a href="https://programmercarl.com/other/kstar.html" target="_blank"> <a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/> <img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a> </a>

View File

@ -706,6 +706,57 @@ class Solution:
``` ```
### Go ### Go
二维dp
```go
func findTargetSumWays(nums []int, target int) int {
sum := 0
for _, v := range nums {
sum += v
}
if math.Abs(float64(target)) > float64(sum) {
return 0 // 此时没有方案
}
if (target + sum) % 2 == 1 {
return 0 // 此时没有方案
}
bagSize := (target + sum) / 2
dp := make([][]int, len(nums))
for i := range dp {
dp[i] = make([]int, bagSize + 1)
}
// 初始化最上行
if nums[0] <= bagSize {
dp[0][nums[0]] = 1
}
// 初始化最左列,最左列其他数值在递推公式中就完成了赋值
dp[0][0] = 1
var numZero float64
for i := range nums {
if nums[i] == 0 {
numZero++
}
dp[i][0] = int(math.Pow(2, numZero))
}
// 以下遍历顺序行列可以颠倒
for i := 1; i < len(nums); i++ { // 行,遍历物品
for j := 0; j <= bagSize; j++ { // 列,遍历背包
if nums[i] > j {
dp[i][j] = dp[i-1][j]
} else {
dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i]]
}
}
}
return dp[len(nums)-1][bagSize]
}
```
一维dp
```go ```go
func findTargetSumWays(nums []int, target int) int { func findTargetSumWays(nums []int, target int) int {
sum := 0 sum := 0

View File

@ -288,6 +288,7 @@ class Solution:
### Go ### Go
一维dp
```go ```go
func change(amount int, coins []int) int { func change(amount int, coins []int) int {
// 定义dp数组 // 定义dp数组
@ -306,6 +307,29 @@ func change(amount int, coins []int) int {
return dp[amount] return dp[amount]
} }
``` ```
二维dp
```go
func change(amount int, coins []int) int {
dp := make([][]int, len(coins))
for i := range dp {
dp[i] = make([]int, amount + 1)
dp[i][0] = 1
}
for j := coins[0]; j <= amount; j++ {
dp[0][j] += dp[0][j-coins[0]]
}
for i := 1; i < len(coins); i++ {
for j := 1; j <= amount; j++ {
if j < coins[i] {
dp[i][j] = dp[i-1][j]
} else {
dp[i][j] = dp[i][j-coins[i]] + dp[i-1][j]
}
}
}
return dp[len(coins)-1][amount]
}
```
### Rust: ### Rust:

View File

@ -492,6 +492,25 @@ int findLengthOfLCIS(int* nums, int numsSize) {
} }
``` ```
### Cangjie
```cangjie
func findLengthOfLCIS(nums: Array<Int64>): Int64 {
let n = nums.size
if (n <= 1) {
return n
}
let dp = Array(n, repeat: 1)
var res = 0
for (i in 1..n) {
if (nums[i] > nums[i - 1]) {
dp[i] = dp[i - 1] + 1
}
res = max(res, dp[i])
}
return res
}
```

View File

@ -581,6 +581,25 @@ int findLength(int* nums1, int nums1Size, int* nums2, int nums2Size) {
} }
``` ```
### Cangjie
```cangjie
func findLength(nums1: Array<Int64>, nums2: Array<Int64>): Int64 {
let n = nums1.size
let m = nums2.size
let dp = Array(n + 1, {_ => Array(m + 1, item: 0)})
var res = 0
for (i in 1..=n) {
for (j in 1..=m) {
if (nums1[i - 1] == nums2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1
}
res = max(res, dp[i][j])
}
}
return res
}
```
<p align="center"> <p align="center">

View File

@ -399,6 +399,25 @@ int longestCommonSubsequence(char* text1, char* text2) {
} }
``` ```
### Cangjie
```cangjie
func longestCommonSubsequence(text1: String, text2: String): Int64 {
let n = text1.size
let m = text2.size
let dp = Array(n + 1, {_ => Array(m + 1, repeat: 0)})
for (i in 1..=n) {
for (j in 1..=m) {
if (text1[i - 1] == text2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1
} else {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
}
}
}
return dp[n][m]
}
```
<p align="center"> <p align="center">

View File

@ -549,6 +549,62 @@ if __name__ == "__main__":
### Javascript ### Javascript
```js
function kruskal(v, edges) {
const father = Array.from({ length: v + 1 }, (_, i) => i)
function find(u){
if (u === father[u]) {
return u
} else {
father[u] = find(father[u])
return father[u]
}
}
function isSame(u, v) {
let s = find(u)
let t = find(v)
return s === t
}
function join(u, v) {
let s = find(u)
let t = find(v)
if (s !== t) {
father[s] = t
}
}
edges.sort((a, b) => a[2] - b[2])
let result = 0
for (const [v1, v2, w] of edges) {
if (!isSame(v1, v2)) {
result += w
join(v1 ,v2)
}
}
console.log(result)
}
async function main() {
const rl = require('readline').createInterface({ input: process.stdin })
const iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
const [v, e] = (await readline()).split(" ").map(Number)
const edges = []
for (let i = 0 ; i < e ; i++) {
edges.push((await readline()).split(" ").map(Number))
}
kruskal(v, edges)
}
main()
```
### TypeScript ### TypeScript
### PhP ### PhP

View File

@ -693,6 +693,55 @@ if __name__ == "__main__":
### Rust ### Rust
### Javascript ### Javascript
```js
function prim(v, edges) {
const grid = Array.from({ length: v + 1 }, () => new Array(v + 1).fill(10001)); // Fixed grid initialization
const minDist = new Array(v + 1).fill(10001)
const isInTree = new Array(v + 1).fill(false)
// 建構鄰接矩陣
for(const [v1, v2, w] of edges) {
grid[v1][v2] = w
grid[v2][v1] = w
}
// prim 演算法
for (let i = 1 ; i < v ; i++) {
let cur = -1
let tempMinDist = Number.MAX_VALUE
// 1. 尋找距離生成樹最近的節點
for (let j = 1 ; j < v + 1 ; j++) {
if (!isInTree[j] && minDist[j] < tempMinDist) {
tempMinDist = minDist[j]
cur = j
}
}
// 2. 將節點放入生成樹
isInTree[cur] = true
// 3. 更新非生成樹節點與生成樹的最短距離
for (let j = 1 ; j < v + 1 ; j++) {
if (!isInTree[j] && grid[cur][j] < minDist[j]) {
minDist[j] = grid[cur][j]
}
}
}
console.log(minDist.slice(2).reduce((acc, cur) => acc + cur, 0))
}
async function main() {
const rl = require('readline').createInterface({ input: process.stdin })
const iter = rl[Symbol.asyncIterator]()
const readline = async () => (await iter.next()).value
const [v, e] = (await readline()).split(" ").map(Number)
const edges = []
for (let i = 0 ; i < e ; i++) {
edges.push((await readline()).split(" ").map(Number))
}
prim(v, edges)
}
main()
```
### TypeScript ### TypeScript

View File

@ -480,7 +480,84 @@ const bfs = (graph, visited, x, y) => {
})() })()
``` ```
```javascript
// 深搜版
const r1 = require('readline').createInterface({ input: process.stdin });
// 创建readline接口
let iter = r1[Symbol.asyncIterator]();
// 创建异步迭代器
const readline = async () => (await iter.next()).value;
let graph // 地图
let N, M // 地图大小
let visited // 访问过的节点
let result = 0 // 最大岛屿面积
let count = 0 // 岛屿内节点数
const dir = [[0, 1], [1, 0], [0, -1], [-1, 0]] //方向
// 读取输入,初始化地图
const initGraph = async () => {
let line = await readline();
[N, M] = line.split(' ').map(Number);
graph = new Array(N).fill(0).map(() => new Array(M).fill(0))
visited = new Array(N).fill(false).map(() => new Array(M).fill(false))
for (let i = 0; i < N; i++) {
line = await readline()
line = line.split(' ').map(Number)
for (let j = 0; j < M; j++) {
graph[i][j] = line[j]
}
}
}
/**
* @description: 从(x, y)开始深度优先遍历
* @param {*} graph 地图
* @param {*} visited 访问过的节点
* @param {*} x 开始搜索节点的下标
* @param {*} y 开始搜索节点的下标
* @return {*}
*/
const dfs = (graph, visited, x, y) => {
for (let i = 0; i < 4; i++) {
let nextx = x + dir[i][0]
let nexty = y + dir[i][1]
if(nextx < 0 || nextx >= N || nexty < 0 || nexty >= M) continue
if(!visited[nextx][nexty] && graph[nextx][nexty] === 1){
count++
visited[nextx][nexty] = true
dfs(graph, visited, nextx, nexty)
}
}
}
(async function () {
// 读取输入,初始化地图
await initGraph()
// 统计最大岛屿面积
for (let i = 0; i < N; i++) {
for (let j = 0; j < M; j++) {
if (!visited[i][j] && graph[i][j] === 1) { //遇到没有访问过的陆地
// 重新计算面积
count = 1
visited[i][j] = true
// 深度优先遍历,统计岛屿内节点数,并将岛屿标记为已访问
dfs(graph, visited, i, j)
// 更新最大岛屿面积
result = Math.max(result, count)
}
}
}
console.log(result);
})()
```
### TypeScript ### TypeScript

View File

@ -307,6 +307,71 @@ for i in range(n):
print(count) print(count)
``` ```
```python
direction = [[1, 0], [-1, 0], [0, 1], [0, -1]]
result = 0
# 深度搜尋
def dfs(grid, y, x):
grid[y][x] = 0
global result
result += 1
for i, j in direction:
next_x = x + j
next_y = y + i
if (next_x < 0 or next_y < 0 or
next_x >= len(grid[0]) or next_y >= len(grid)
):
continue
if grid[next_y][next_x] == 1 and not visited[next_y][next_x]:
visited[next_y][next_x] = True
dfs(grid, next_y, next_x)
# 讀取輸入值
n, m = map(int, input().split())
grid = []
visited = [[False] * m for _ in range(n)]
for i in range(n):
grid.append(list(map(int, input().split())))
# 處理邊界
for j in range(m):
# 上邊界
if grid[0][j] == 1 and not visited[0][j]:
visited[0][j] = True
dfs(grid, 0, j)
# 下邊界
if grid[n - 1][j] == 1 and not visited[n - 1][j]:
visited[n - 1][j] = True
dfs(grid, n - 1, j)
for i in range(n):
# 左邊界
if grid[i][0] == 1 and not visited[i][0]:
visited[i][0] = True
dfs(grid, i, 0)
# 右邊界
if grid[i][m - 1] == 1 and not visited[i][m - 1]:
visited[i][m - 1] = True
dfs(grid, i, m - 1)
# 計算孤島總面積
result = 0 # 初始化,避免使用到處理邊界時所產生的累加值
for i in range(n):
for j in range(m):
if grid[i][j] == 1 and not visited[i][j]:
visited[i][j] = True
dfs(grid, i, j)
# 輸出孤島的總面積
print(result)
```
### Go ### Go
``` go ``` go

View File

@ -178,6 +178,45 @@ int main() {
### Python ### Python
```python
father = list()
def find(u):
if u == father[u]:
return u
else:
father[u] = find(father[u])
return father[u]
def is_same(u, v):
u = find(u)
v = find(v)
return u == v
def join(u, v):
u = find(u)
v = find(v)
if u != v:
father[u] = v
if __name__ == "__main__":
# 輸入
n = int(input())
for i in range(n + 1):
father.append(i)
# 尋找冗余邊
result = None
for i in range(n):
s, t = map(int, input().split())
if is_same(s, t):
result = str(s) + ' ' + str(t)
else:
join(s, t)
# 輸出
print(result)
```
### Go ### Go
### Rust ### Rust

View File

@ -250,9 +250,193 @@ int main() {
## 其他语言版本 ## 其他语言版本
### Java ### Java
```java
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
static int n;
static int[] father = new int[1001]; // 并查集数组
// 并查集初始化
public static void init() {
for (int i = 1; i <= n; ++i) {
father[i] = i;
}
}
// 并查集里寻根的过程
public static int find(int u) {
if (u == father[u]) return u;
return father[u] = find(father[u]); // 路径压缩
}
// 将 v->u 这条边加入并查集
public static void join(int u, int v) {
u = find(u);
v = find(v);
if (u != v) {
father[v] = u; // 合并两棵树
}
}
// 判断 u 和 v 是否有同一个根
public static boolean same(int u, int v) {
return find(u) == find(v);
}
// 在有向图里找到删除的那条边,使其变成树
public static void getRemoveEdge(List<int[]> edges) {
init(); // 初始化并查集
for (int i = 0; i < n; i++) { // 遍历所有的边
if (same(edges.get(i)[0], edges.get(i)[1])) { // 如果构成有向环了,就是要删除的边
System.out.println(edges.get(i)[0] + " " + edges.get(i)[1]);
return;
} else {
join(edges.get(i)[0], edges.get(i)[1]);
}
}
}
// 删一条边之后判断是不是树
public static boolean isTreeAfterRemoveEdge(List<int[]> edges, int deleteEdge) {
init(); // 初始化并查集
for (int i = 0; i < n; i++) {
if (i == deleteEdge) continue;
if (same(edges.get(i)[0], edges.get(i)[1])) { // 如果构成有向环了,一定不是树
return false;
}
join(edges.get(i)[0], edges.get(i)[1]);
}
return true;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
List<int[]> edges = new ArrayList<>(); // 存储所有的边
n = sc.nextInt(); // 顶点数
int[] inDegree = new int[n + 1]; // 记录每个节点的入度
for (int i = 0; i < n; i++) {
int s = sc.nextInt(); // 边的起点
int t = sc.nextInt(); // 边的终点
inDegree[t]++;
edges.add(new int[]{s, t}); // 将边加入列表
}
List<Integer> vec = new ArrayList<>(); // 记录入度为2的边如果有的话就两条边
// 找入度为2的节点所对应的边注意要倒序因为优先删除最后出现的一条边
for (int i = n - 1; i >= 0; i--) {
if (inDegree[edges.get(i)[1]] == 2) {
vec.add(i);
}
}
// 情况一、情况二
if (vec.size() > 0) {
// vec里的边已经按照倒叙放的所以优先删 vec.get(0) 这条边
if (isTreeAfterRemoveEdge(edges, vec.get(0))) {
System.out.println(edges.get(vec.get(0))[0] + " " + edges.get(vec.get(0))[1]);
} else {
System.out.println(edges.get(vec.get(1))[0] + " " + edges.get(vec.get(1))[1]);
}
return;
}
// 处理情况三明确没有入度为2的情况一定有有向环找到构成环的边返回即可
getRemoveEdge(edges);
}
}
```
### Python ### Python
```python
from collections import defaultdict
father = list()
def find(u):
if u == father[u]:
return u
else:
father[u] = find(father[u])
return father[u]
def is_same(u, v):
u = find(u)
v = find(v)
return u == v
def join(u, v):
u = find(u)
v = find(v)
if u != v:
father[u] = v
def is_tree_after_remove_edge(edges, edge, n):
# 初始化并查集
global father
father = [i for i in range(n + 1)]
for i in range(len(edges)):
if i == edge:
continue
s, t = edges[i]
if is_same(s, t): # 成環,即不是有向樹
return False
else: # 將s,t放入集合中
join(s, t)
return True
def get_remove_edge(edges):
# 初始化并查集
global father
father = [i for i in range(n + 1)]
for s, t in edges:
if is_same(s, t):
print(s, t)
return
else:
join(s, t)
if __name__ == "__main__":
# 輸入
n = int(input())
edges = list()
in_degree = defaultdict(int)
for i in range(n):
s, t = map(int, input().split())
in_degree[t] += 1
edges.append([s, t])
# 尋找入度為2的邊並紀錄其下標(index)
vec = list()
for i in range(n - 1, -1, -1):
if in_degree[edges[i][1]] == 2:
vec.append(i)
# 輸出
if len(vec) > 0:
# 情況一:刪除輸出順序靠後的邊
if is_tree_after_remove_edge(edges, vec[0], n):
print(edges[vec[0]][0], edges[vec[0]][1])
# 情況二:只能刪除特定的邊
else:
print(edges[vec[1]][0], edges[vec[1]][1])
else:
# 情況三: 原圖有環
get_remove_edge(edges)
```
### Go ### Go
### Rust ### Rust