Skip to content

Commit 79dd9e8

Browse files
committed
Add LeetCode Weekly Contest 271
1 parent 0c2b773 commit 79dd9e8

File tree

8 files changed

+367
-0
lines changed

8 files changed

+367
-0
lines changed

leetcode/weekly/271/a/a.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package main
2+
3+
// 位运算做法
4+
5+
// github.com/EndlessCheng/codeforces-go
6+
var mp = []int{'B': 1, 'G': 2, 'R': 4}
7+
8+
func countPoints(s string) (ans int) {
9+
masks := [10]int{}
10+
for i := 0; i < len(s); i += 2 {
11+
masks[s[i+1]-'0'] |= mp[s[i]]
12+
}
13+
for _, m := range masks {
14+
if m == 7 { // 7 = 1 + 2 + 4
15+
ans++
16+
}
17+
}
18+
return
19+
}

leetcode/weekly/271/a/a_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.

leetcode/weekly/271/b/b.go

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package main
2+
3+
/*
4+
从 O(n^2) 到 O(n):单调栈+计算每个元素对答案的贡献
5+
6+
#### 方法一:暴力枚举所有子数组
7+
8+
写一个二重循环,外层循环枚举子数组的左边界,内层循环枚举子数组的右边界,同时维护当前子数组的最小值和最大值。
9+
10+
```go
11+
func subArrayRanges(nums []int) (ans int64) {
12+
for i, num := range nums {
13+
min, max := num, num
14+
for _, v := range nums[i+1:] {
15+
if v < min {
16+
min = v
17+
} else if v > max {
18+
max = v
19+
}
20+
ans += int64(max - min)
21+
}
22+
}
23+
return
24+
}
25+
```
26+
27+
**复杂度分析**
28+
29+
- 时间复杂度:$O(n^2)$,其中 $n$ 是数组 $\textit{nums}$ 的长度。
30+
31+
- 空间复杂度:$O(1)$,我们只需要常数的空间保存若干变量。
32+
33+
#### 方法二:单调栈 + 计算每个元素对答案的贡献
34+
35+
不了解单调栈的同学可以看一下 496 题。
36+
37+
我们可以考虑每个元素作为最大值出现在了多少子数组中,以及作为最小值出现在了多少子数组中。
38+
39+
以最大值为例。我们可以求出 $\textit{nums}[i]$ 左侧**严格大于**它的最近元素位置 $\textit{left}[i]$,以及右侧**大于等于**它的元素位置 $\textit{right}[i]$。注意 $\textit{nums}$ 中可能有重复元素,所以这里右侧取大于等于,这样可以避免在有重复元素的情况下,重复统计相同的子数组。
40+
41+
设以 $\textit{nums}[i]$ 为最大值的子数组为 $\textit{nums}[l..r]$,则有
42+
43+
- $\textit{left}[i]<l\le i$
44+
- $i\le r<\textit{right}[i]$
45+
46+
所以 $\textit{nums}[i]$ 可以作为最大值出现在
47+
48+
$$
49+
(i-\textit{left}[i])\cdot (\textit{right}[i]-i)
50+
$$
51+
52+
个子数组中,这对答案产生的贡献是
53+
54+
$$
55+
(i-\textit{left}[i])\cdot(\textit{right}[i]-i)\cdot \textit{nums}[i]
56+
$$
57+
58+
最小值的做法同理(注意贡献为负数)。
59+
60+
累加所有贡献即为答案。
61+
62+
```go
63+
64+
```
65+
66+
**复杂度分析**
67+
68+
- 时间复杂度:$O(n)$,其中 $n$ 是数组 $\textit{nums}$ 的长度。
69+
70+
- 空间复杂度:$O(n)$。
71+
72+
*/
73+
74+
// github.com/EndlessCheng/codeforces-go
75+
func subArrayRanges2(nums []int) (ans int64) {
76+
for i, num := range nums {
77+
min, max := num, num
78+
for _, v := range nums[i+1:] {
79+
if v < min {
80+
min = v
81+
} else if v > max {
82+
max = v
83+
}
84+
ans += int64(max - min)
85+
}
86+
}
87+
return
88+
}
89+
90+
// github.com/EndlessCheng/codeforces-go
91+
func subArrayRanges(nums []int) int64 {
92+
n := len(nums)
93+
left := make([]int, n) // left[i] 为左侧严格大于 num[i] 的最近元素位置(不存在时为 -1)
94+
type pair struct{ v, i int }
95+
s := []pair{{2e9, -1}} // 哨兵
96+
for i, v := range nums {
97+
for s[len(s)-1].v <= v { s = s[:len(s)-1] }
98+
left[i] = s[len(s)-1].i
99+
s = append(s, pair{v, i})
100+
}
101+
102+
right := make([]int, n) // right[i] 为右侧大于等于 num[i] 的最近元素位置(不存在时为 n)
103+
s = []pair{{2e9, n}}
104+
for i := n - 1; i >= 0; i-- {
105+
v := nums[i]
106+
for s[len(s)-1].v < v { s = s[:len(s)-1] }
107+
right[i] = s[len(s)-1].i
108+
s = append(s, pair{v, i})
109+
}
110+
111+
ans := 0
112+
for i, v := range nums {
113+
ans += (i - left[i]) * (right[i] - i) * v
114+
}
115+
116+
// 求左侧严格小于
117+
left = make([]int, n) // left[i] 为左侧严格小于 num[i] 的最近元素位置(不存在时为 -1)
118+
s = []pair{{-2e9, -1}}
119+
for i, v := range nums {
120+
for s[len(s)-1].v >= v { s = s[:len(s)-1] }
121+
left[i] = s[len(s)-1].i
122+
s = append(s, pair{v, i})
123+
}
124+
125+
right = make([]int, n) // right[i] 为右侧小于等于 num[i] 的最近元素位置(不存在时为 n)
126+
s = []pair{{-2e9, n}}
127+
for i := n - 1; i >= 0; i-- {
128+
v := nums[i]
129+
for s[len(s)-1].v > v { s = s[:len(s)-1] }
130+
right[i] = s[len(s)-1].i
131+
s = append(s, pair{v, i})
132+
}
133+
134+
for i, v := range nums {
135+
ans -= (i - left[i]) * (right[i] - i) * v
136+
}
137+
138+
return int64(ans)
139+
}

leetcode/weekly/271/b/b_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.

leetcode/weekly/271/c/c.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package main
2+
3+
// 双指针模拟
4+
5+
// github.com/EndlessCheng/codeforces-go
6+
func minimumRefill(plants []int, capacityA, capacityB int) (ans int) {
7+
a, b := capacityA, capacityB
8+
for i, j := 0, len(plants)-1; i <= j; {
9+
if i == j {
10+
if a < plants[i] && b < plants[i] { // 两人都无法浇水
11+
ans++
12+
}
13+
break
14+
}
15+
if a < plants[i] {
16+
a = capacityA
17+
ans++
18+
}
19+
a -= plants[i]
20+
i++
21+
if b < plants[j] {
22+
b = capacityB
23+
ans++
24+
}
25+
b -= plants[j]
26+
j--
27+
}
28+
return
29+
}

leetcode/weekly/271/c/c_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/271/d/d.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package main
2+
3+
import "sort"
4+
5+
// github.com/EndlessCheng/codeforces-go
6+
func maxTotalFruits(fruits [][]int, startPos int, k int) (ans int) {
7+
n := len(fruits)
8+
sum := make([]int, n+1)
9+
for i, f := range fruits {
10+
sum[i+1] = sum[i] + f[1]
11+
}
12+
13+
// 先向右再向左
14+
mid := sort.Search(n, func(i int) bool { return fruits[i][0] >= startPos })
15+
for i := mid; i < n; i++ {
16+
d := fruits[i][0] - startPos
17+
if d > k {
18+
break
19+
}
20+
cnt := sum[i+1] - sum[mid]
21+
d *= 2
22+
if d < k {
23+
// 往左最远能到达的水果下标
24+
left := sort.Search(n, func(i int) bool { return fruits[i][0] >= startPos-k+d })
25+
cnt += sum[mid] - sum[left]
26+
}
27+
ans = max(ans, cnt)
28+
}
29+
30+
// 先向左再向右
31+
for i := mid - 1; i >= 0; i-- {
32+
d := startPos - fruits[i][0]
33+
if d > k {
34+
break
35+
}
36+
cnt := sum[mid] - sum[i]
37+
d *= 2
38+
if d < k {
39+
// 往右最远能到达的水果下标+1
40+
right := sort.Search(n, func(i int) bool { return fruits[i][0] > startPos+k-d })
41+
cnt += sum[right] - sum[mid]
42+
}
43+
ans = max(ans, cnt)
44+
}
45+
return
46+
}
47+
48+
func max(a, b int) int { if b > a { return b }; return a }

leetcode/weekly/271/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)