Skip to content

Commit b862126

Browse files
committed
Add LeetCode Weekly Contest 270
1 parent 7ba6557 commit b862126

File tree

8 files changed

+348
-0
lines changed

8 files changed

+348
-0
lines changed

leetcode/weekly/270/a/a.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package main
2+
3+
// 枚举所有三位数偶数
4+
5+
// github.com/EndlessCheng/codeforces-go
6+
func findEvenNumbers(digits []int) (ans []int) {
7+
cnt := [10]int{}
8+
for _, d := range digits {
9+
cnt[d]++
10+
}
11+
next:
12+
for i := 100; i < 1000; i += 2 { // 枚举所有三位数偶数 i
13+
c := [10]int{}
14+
for x := i; x > 0; x /= 10 { // 枚举 i 的每一位 d
15+
d := x % 10
16+
if c[d]++; c[d] > cnt[d] { // 如果 d 出现次数比 digits 中的 d 的次数还多,那么 i 肯定不能由 digits 中的数字组成
17+
continue next // 枚举下一个偶数
18+
}
19+
}
20+
ans = append(ans, i)
21+
}
22+
return
23+
}

leetcode/weekly/270/a/a_test.go

Lines changed: 39 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

leetcode/weekly/270/b/b.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package main
2+
3+
import . "github.com/EndlessCheng/codeforces-go/leetcode/testutil"
4+
5+
/* 快慢指针
6+
7+
这题其实就是把 [876. 链表的中间结点](https://leetcode-cn.com/problems/middle-of-the-linked-list/) 和删除链表结点结合起来
8+
9+
我们只需要在 876 题的基础上,额外记录 $\textit{slow}$ 结点的上一个结点即可。
10+
11+
*/
12+
13+
// github.com/EndlessCheng/codeforces-go
14+
func deleteMiddle(head *ListNode) *ListNode {
15+
dummyHead := &ListNode{Next: head}
16+
pre, slow, fast := dummyHead, head, head
17+
for fast != nil && fast.Next != nil {
18+
pre = slow // pre 记录了 slow 的上一个结点
19+
slow = slow.Next
20+
fast = fast.Next.Next
21+
}
22+
// 循环结束后,slow 为待删除结点
23+
pre.Next = slow.Next // 删除 slow
24+
return dummyHead.Next
25+
}

leetcode/weekly/270/b/b_test.go

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

leetcode/weekly/270/c/c.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package main
2+
3+
import (
4+
. "github.com/EndlessCheng/codeforces-go/leetcode/testutil"
5+
"strings"
6+
)
7+
8+
/* 一题双解:BFS / 最近公共祖先
9+
10+
#### 解法一:DFS + BFS
11+
12+
我们可以从起点出发,通过 BFS 找到终点,同时记录每个点的来源节点和方向,在找到终点后,顺着来源节点往回走,同时记录答案。
13+
14+
由于要往父节点方向走,我们需要先通过一次 DFS 记录每个节点的父节点,这样就可以在 BFS 中往父节点和左右节点三个方向前进了。
15+
16+
DFS 的过程中也可以顺带找到起点。
17+
18+
#### 解法二:最近公共祖先
19+
20+
按照 [236. 二叉树的最近公共祖先](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/) 给出的方法,我们可以从起点出发,找到到起点和终点的路径,然后去掉前缀相同的部分。剩下即为从起点和终点的最近公共祖先出发,到起点和终点的路径,分别记作 $\textit{pathToStart}$ 和 $\textit{pathToDest}$。
21+
22+
我们要找的最短路径即为:起点 => 起点和终点的最近公共祖先 => 终点。
23+
24+
对于起点到最近公共祖先这一段,可以看成长度为 $\textit{pathToStart}$ 的向父节点走的路径;对于最近公共祖先到终点这一段就是 $\textit{pathToDest}$。将这两段路径拼起来即为答案。
25+
26+
*/
27+
28+
// github.com/EndlessCheng/codeforces-go
29+
func getDirections(root *TreeNode, startValue, destValue int) string {
30+
var path []byte
31+
var dfs func(*TreeNode, int) bool
32+
dfs = func(node *TreeNode, target int) bool {
33+
if node == nil {
34+
return false
35+
}
36+
if node.Val == target {
37+
return true
38+
}
39+
path = append(path, 'L')
40+
if dfs(node.Left, target) {
41+
return true
42+
}
43+
path[len(path)-1] = 'R'
44+
if dfs(node.Right, target) {
45+
return true
46+
}
47+
path = path[:len(path)-1]
48+
return false
49+
}
50+
dfs(root, startValue)
51+
pathToStart := path
52+
53+
path = nil
54+
dfs(root, destValue)
55+
pathToDest := path
56+
57+
for len(pathToStart) > 0 && len(pathToDest) > 0 && pathToStart[0] == pathToDest[0] {
58+
pathToStart = pathToStart[1:]
59+
pathToDest = pathToDest[1:]
60+
}
61+
62+
return strings.Repeat("U", len(pathToStart)) + string(pathToDest)
63+
}
64+
65+
func getDirections2(root *TreeNode, startValue, destValue int) string {
66+
q := []*TreeNode{nil}
67+
parents := map[*TreeNode]*TreeNode{}
68+
var dfs func(node, pa *TreeNode)
69+
dfs = func(node, pa *TreeNode) {
70+
if node == nil {
71+
return
72+
}
73+
parents[node] = pa
74+
if node.Val == startValue {
75+
q[0] = node // 只有一个起点
76+
}
77+
dfs(node.Left, node)
78+
dfs(node.Right, node)
79+
}
80+
dfs(root, nil)
81+
82+
ans := []byte{}
83+
vis := map[*TreeNode]bool{nil: true, q[0]: true}
84+
type pair struct {
85+
from *TreeNode
86+
dir byte
87+
}
88+
from := map[*TreeNode]pair{}
89+
for len(q) > 0 {
90+
node := q[0]
91+
q = q[1:]
92+
if node.Val == destValue {
93+
for ; from[node].from != nil; node = from[node].from {
94+
ans = append(ans, from[node].dir)
95+
}
96+
break
97+
}
98+
if !vis[node.Left] {
99+
vis[node.Left] = true
100+
from[node.Left] = pair{node, 'L'}
101+
q = append(q, node.Left)
102+
}
103+
if !vis[node.Right] {
104+
vis[node.Right] = true
105+
from[node.Right] = pair{node, 'R'}
106+
q = append(q, node.Right)
107+
}
108+
if !vis[parents[node]] {
109+
vis[parents[node]] = true
110+
from[parents[node]] = pair{node, 'U'}
111+
q = append(q, parents[node])
112+
}
113+
}
114+
for i, n := 0, len(ans); i < n/2; i++ {
115+
ans[i], ans[n-1-i] = ans[n-1-i], ans[i]
116+
}
117+
return string(ans)
118+
}

leetcode/weekly/270/c/c_test.go

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

leetcode/weekly/270/d/d.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package main
2+
3+
/* 有向图欧拉路径
4+
5+
本题与 [332. 重新安排行程](https://leetcode-cn.com/problems/reconstruct-itinerary/) 一样,都可以抽象成如下问题:
6+
7+
> 给你一张有向图,在这张有向图中找到一条欧拉路径。
8+
9+
对于此题,由于题目保证有解,所以有向图肯定是欧拉图或半欧拉图。
10+
11+
我们需要找到一个起点,如果是欧拉图,那么随便找一个点都行,如果是半欧拉图,那么找到一个出度比入度大 1 的点,把它当成起点,然后按照 332 给出的算法来求解。
12+
13+
*/
14+
15+
// github.com/EndlessCheng/codeforces-go
16+
func validArrangement(pairs [][]int) [][]int {
17+
type edge struct{ to, idx int }
18+
g := map[int][]edge{}
19+
inDeg := map[int]int{}
20+
for i, p := range pairs {
21+
v, w := p[0], p[1]
22+
g[v] = append(g[v], edge{w, i}) // 建图(有向图)
23+
inDeg[w]++ // 统计入度
24+
}
25+
26+
start := 0
27+
for i, es := range g {
28+
if len(es) == inDeg[i]+1 { // 如果存在出度比入度大 1 的点,那就把它当成起点
29+
start = i
30+
break
31+
}
32+
start = i // 或者随便找一个点当起点
33+
}
34+
35+
m := len(pairs)
36+
ans := make([][]int, 0, m)
37+
var dfs func(int)
38+
dfs = func(v int) {
39+
for len(g[v]) > 0 {
40+
e := g[v][0]
41+
g[v] = g[v][1:]
42+
dfs(e.to)
43+
ans = append(ans, pairs[e.idx]) // 保存所有边
44+
}
45+
}
46+
dfs(start)
47+
for i := 0; i < m/2; i++ {
48+
ans[i], ans[m-1-i] = ans[m-1-i], ans[i]
49+
}
50+
return ans
51+
}

leetcode/weekly/270/d/d_test.go

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)