Skip to content

Commit de1673a

Browse files
committed
feat: add solutions to lc problem: No.2612
No.2612.Minimum Reverse Operations
1 parent 358f91d commit de1673a

File tree

6 files changed

+322
-49
lines changed

6 files changed

+322
-49
lines changed

solution/2600-2699/2612.Minimum Reverse Operations/README.md

Lines changed: 124 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,30 @@
6868

6969
<!-- 这里可写通用的实现逻辑 -->
7070

71+
**方法一:有序集合 + BFS**
72+
73+
我们注意到,对于一个子数组区间 $[l,..r]$ 中的任意一个下标 $i$,翻转后的下标 $j = l + r - i$。
74+
75+
如果子数组向右移动一个位置,那么 $j = l + 1 + r + 1 - i = l + r - i + 2$,即 $j$ 会增加 $2$。
76+
77+
同理,如果子数组向左移动一个位置,那么 $j = l - 1 + r - 1 - i = l + r - i - 2$,即 $j$ 会减少 $2$。
78+
79+
因此,对于一个特定的下标 $i$,其翻转后的所有位置构成了一个公差为 $2$ 的等差数列,也即是说,翻转后的所有下标,奇偶性都是相同的。
80+
81+
接下来,我们考虑下标 $i$ 翻转后的位置 $j$ 的取值范围。
82+
83+
- 如果不考虑边界的情况,那么 $j$ 的取值范围为 $[i - k + 1, i + k - 1]$。
84+
- 如果子数组在最左边,那么 $[l, r] = [0, k - 1]$,因此 $i$ 翻转后的下标 $j = 0 + k - 1 - i$,即 $j = k - i - 1$,因此 $j$ 的左边界 $mi = max(i - k + 1, k - i - 1)$。
85+
- 如果子数组在最右边,那么 $[l, r] = [n - k, n - 1]$,因此 $i$ 翻转后的下标 $j= n - k + n - 1 - i$,即 $j = n \times 2 - k - i - 1$,因此 $j$ 的右边界 $mx = min(i + k - 1, n \times 2 - k - i - 1)$。
86+
87+
我们用两个有序集合分别存储所有待搜索的奇数下标和偶数下标,这里需要排除数组 $banned$ 中的下标,以及下标 $p$。
88+
89+
接下来,我们使用 BFS 搜索,每次搜索当前下标 $i$ 所有翻转后的下标 $j$,即 $j = mi, mi + 2, mi + 4, \dots, mx$,更新下标 $j$ 的答案,并将下标 $j$ 加入到待搜索的队列中,同时将下标 $j$ 从对应的有序集合中移除。
90+
91+
当搜索结束时,即可得到所有下标的答案。
92+
93+
时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 题目中给定的数组长度。
94+
7195
<!-- tabs:start -->
7296

7397
### **Python3**
@@ -79,7 +103,9 @@ from sortedcontainers import SortedSet
79103

80104

81105
class Solution:
82-
def minReverseOperations(self, n: int, p: int, banned: List[int], k: int) -> List[int]:
106+
def minReverseOperations(
107+
self, n: int, p: int, banned: List[int], k: int
108+
) -> List[int]:
83109
ans = [-1] * n
84110
ans[p] = 0
85111
ts = [SortedSet() for _ in range(2)]
@@ -88,16 +114,20 @@ class Solution:
88114
ts[p % 2].remove(p)
89115
for i in banned:
90116
ts[i % 2].remove(i)
117+
ts[0].add(n)
118+
ts[1].add(n)
91119
q = deque([p])
92120
while q:
93-
x = q.popleft()
94-
i = abs(x - k + 1)
95-
j = ts[i % 2].bisect_left(i)
96-
while j < len(ts[i % 2]) and ts[i % 2][j] < n - abs(n - x - k):
97-
q.append(ts[i % 2][j])
98-
ans[ts[i % 2][j]] = ans[x] + 1
99-
ts[i % 2].remove(ts[i % 2][j])
100-
j = ts[i % 2].bisect_left(i)
121+
i = q.popleft()
122+
mi = max(i - k + 1, k - i - 1)
123+
mx = min(i + k - 1, n * 2 - k - i - 1)
124+
s = ts[mi % 2]
125+
j = s.bisect_left(mi)
126+
while s[j] <= mx:
127+
q.append(s[j])
128+
ans[s[j]] = ans[i] + 1
129+
s.remove(s[j])
130+
j = s.bisect_left(mi)
101131
return ans
102132
```
103133

@@ -118,17 +148,19 @@ class Solution {
118148
for (int i : banned) {
119149
ts[i % 2].remove(i);
120150
}
151+
ts[0].add(n);
152+
ts[1].add(n);
121153
Deque<Integer> q = new ArrayDeque<>();
122154
q.offer(p);
123155
while (!q.isEmpty()) {
124-
int x = q.poll();
125-
int i = Math.abs(x - k + 1);
126-
Integer j = ts[i % 2].ceiling(i);
127-
while (j != null && j < n - Math.abs(n - x - k)) {
156+
int i = q.poll();
157+
int mi = Math.max(i - k + 1, k - i - 1);
158+
int mx = Math.min(i + k - 1, n * 2 - k - i - 1);
159+
var s = ts[mi % 2];
160+
for (int j = s.ceiling(mi); j <= mx; j = s.ceiling(mi)) {
128161
q.offer(j);
129-
ans[j] = ans[x] + 1;
130-
ts[i % 2].remove(j);
131-
j = ts[i % 2].higher(j);
162+
ans[j] = ans[i] + 1;
163+
s.remove(j);
132164
}
133165
}
134166
return ans;
@@ -139,13 +171,88 @@ class Solution {
139171
### **C++**
140172

141173
```cpp
142-
174+
class Solution {
175+
public:
176+
vector<int> minReverseOperations(int n, int p, vector<int>& banned, int k) {
177+
vector<int> ans(n, -1);
178+
ans[p] = 0;
179+
set<int> ts[2];
180+
for (int i = 0; i < n; ++i) {
181+
ts[i % 2].insert(i);
182+
}
183+
ts[p % 2].erase(p);
184+
for (int i : banned) {
185+
ts[i % 2].erase(i);
186+
}
187+
ts[0].insert(n);
188+
ts[1].insert(n);
189+
queue<int> q{{p}};
190+
while (!q.empty()) {
191+
int i = q.front();
192+
q.pop();
193+
int mi = max(i - k + 1, k - i - 1);
194+
int mx = min(i + k - 1, n * 2 - k - i - 1);
195+
auto& s = ts[mi % 2];
196+
auto it = s.lower_bound(mi);
197+
while (*it <= mx) {
198+
int j = *it;
199+
ans[j] = ans[i] + 1;
200+
q.push(j);
201+
it = s.erase(it);
202+
}
203+
}
204+
return ans;
205+
}
206+
};
143207
```
144208
145209
### **Go**
146210
147211
```go
212+
func minReverseOperations(n int, p int, banned []int, k int) []int {
213+
ans := make([]int, n)
214+
ts := [2]*redblacktree.Tree{redblacktree.NewWithIntComparator(), redblacktree.NewWithIntComparator()}
215+
for i := 0; i < n; i++ {
216+
ts[i%2].Put(i, struct{}{})
217+
ans[i] = -1
218+
}
219+
ans[p] = 0
220+
ts[p%2].Remove(p)
221+
for _, i := range banned {
222+
ts[i%2].Remove(i)
223+
}
224+
ts[0].Put(n, struct{}{})
225+
ts[1].Put(n, struct{}{})
226+
q := []int{p}
227+
for len(q) > 0 {
228+
i := q[0]
229+
q = q[1:]
230+
mi := max(i-k+1, k-i-1)
231+
mx := min(i+k-1, n*2-k-i-1)
232+
s := ts[mi%2]
233+
for x, _ := s.Ceiling(mi); x.Key.(int) <= mx; x, _ = s.Ceiling(mi) {
234+
j := x.Key.(int)
235+
s.Remove(j)
236+
ans[j] = ans[i] + 1
237+
q = append(q, j)
238+
}
239+
}
240+
return ans
241+
}
148242
243+
func max(a, b int) int {
244+
if a > b {
245+
return a
246+
}
247+
return b
248+
}
249+
250+
func min(a, b int) int {
251+
if a < b {
252+
return a
253+
}
254+
return b
255+
}
149256
```
150257

151258
### **...**

solution/2600-2699/2612.Minimum Reverse Operations/README_EN.md

Lines changed: 100 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ from sortedcontainers import SortedSet
6767

6868

6969
class Solution:
70-
def minReverseOperations(self, n: int, p: int, banned: List[int], k: int) -> List[int]:
70+
def minReverseOperations(
71+
self, n: int, p: int, banned: List[int], k: int
72+
) -> List[int]:
7173
ans = [-1] * n
7274
ans[p] = 0
7375
ts = [SortedSet() for _ in range(2)]
@@ -76,16 +78,20 @@ class Solution:
7678
ts[p % 2].remove(p)
7779
for i in banned:
7880
ts[i % 2].remove(i)
81+
ts[0].add(n)
82+
ts[1].add(n)
7983
q = deque([p])
8084
while q:
81-
x = q.popleft()
82-
i = abs(x - k + 1)
83-
j = ts[i % 2].bisect_left(i)
84-
while j < len(ts[i % 2]) and ts[i % 2][j] < n - abs(n - x - k):
85-
q.append(ts[i % 2][j])
86-
ans[ts[i % 2][j]] = ans[x] + 1
87-
ts[i % 2].remove(ts[i % 2][j])
88-
j = ts[i % 2].bisect_left(i)
85+
i = q.popleft()
86+
mi = max(i - k + 1, k - i - 1)
87+
mx = min(i + k - 1, n * 2 - k - i - 1)
88+
s = ts[mi % 2]
89+
j = s.bisect_left(mi)
90+
while s[j] <= mx:
91+
q.append(s[j])
92+
ans[s[j]] = ans[i] + 1
93+
s.remove(s[j])
94+
j = s.bisect_left(mi)
8995
return ans
9096
```
9197

@@ -104,17 +110,19 @@ class Solution {
104110
for (int i : banned) {
105111
ts[i % 2].remove(i);
106112
}
113+
ts[0].add(n);
114+
ts[1].add(n);
107115
Deque<Integer> q = new ArrayDeque<>();
108116
q.offer(p);
109117
while (!q.isEmpty()) {
110-
int x = q.poll();
111-
int i = Math.abs(x - k + 1);
112-
Integer j = ts[i % 2].ceiling(i);
113-
while (j != null && j < n - Math.abs(n - x - k)) {
118+
int i = q.poll();
119+
int mi = Math.max(i - k + 1, k - i - 1);
120+
int mx = Math.min(i + k - 1, n * 2 - k - i - 1);
121+
var s = ts[mi % 2];
122+
for (int j = s.ceiling(mi); j <= mx; j = s.ceiling(mi)) {
114123
q.offer(j);
115-
ans[j] = ans[x] + 1;
116-
ts[i % 2].remove(j);
117-
j = ts[i % 2].higher(j);
124+
ans[j] = ans[i] + 1;
125+
s.remove(j);
118126
}
119127
}
120128
return ans;
@@ -125,13 +133,88 @@ class Solution {
125133
### **C++**
126134

127135
```cpp
128-
136+
class Solution {
137+
public:
138+
vector<int> minReverseOperations(int n, int p, vector<int>& banned, int k) {
139+
vector<int> ans(n, -1);
140+
ans[p] = 0;
141+
set<int> ts[2];
142+
for (int i = 0; i < n; ++i) {
143+
ts[i % 2].insert(i);
144+
}
145+
ts[p % 2].erase(p);
146+
for (int i : banned) {
147+
ts[i % 2].erase(i);
148+
}
149+
ts[0].insert(n);
150+
ts[1].insert(n);
151+
queue<int> q{{p}};
152+
while (!q.empty()) {
153+
int i = q.front();
154+
q.pop();
155+
int mi = max(i - k + 1, k - i - 1);
156+
int mx = min(i + k - 1, n * 2 - k - i - 1);
157+
auto& s = ts[mi % 2];
158+
auto it = s.lower_bound(mi);
159+
while (*it <= mx) {
160+
int j = *it;
161+
ans[j] = ans[i] + 1;
162+
q.push(j);
163+
it = s.erase(it);
164+
}
165+
}
166+
return ans;
167+
}
168+
};
129169
```
130170
131171
### **Go**
132172
133173
```go
174+
func minReverseOperations(n int, p int, banned []int, k int) []int {
175+
ans := make([]int, n)
176+
ts := [2]*redblacktree.Tree{redblacktree.NewWithIntComparator(), redblacktree.NewWithIntComparator()}
177+
for i := 0; i < n; i++ {
178+
ts[i%2].Put(i, struct{}{})
179+
ans[i] = -1
180+
}
181+
ans[p] = 0
182+
ts[p%2].Remove(p)
183+
for _, i := range banned {
184+
ts[i%2].Remove(i)
185+
}
186+
ts[0].Put(n, struct{}{})
187+
ts[1].Put(n, struct{}{})
188+
q := []int{p}
189+
for len(q) > 0 {
190+
i := q[0]
191+
q = q[1:]
192+
mi := max(i-k+1, k-i-1)
193+
mx := min(i+k-1, n*2-k-i-1)
194+
s := ts[mi%2]
195+
for x, _ := s.Ceiling(mi); x.Key.(int) <= mx; x, _ = s.Ceiling(mi) {
196+
j := x.Key.(int)
197+
s.Remove(j)
198+
ans[j] = ans[i] + 1
199+
q = append(q, j)
200+
}
201+
}
202+
return ans
203+
}
134204
205+
func max(a, b int) int {
206+
if a > b {
207+
return a
208+
}
209+
return b
210+
}
211+
212+
func min(a, b int) int {
213+
if a < b {
214+
return a
215+
}
216+
return b
217+
}
135218
```
136219

137220
### **...**
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
class Solution {
2+
public:
3+
vector<int> minReverseOperations(int n, int p, vector<int>& banned, int k) {
4+
vector<int> ans(n, -1);
5+
ans[p] = 0;
6+
set<int> ts[2];
7+
for (int i = 0; i < n; ++i) {
8+
ts[i % 2].insert(i);
9+
}
10+
ts[p % 2].erase(p);
11+
for (int i : banned) {
12+
ts[i % 2].erase(i);
13+
}
14+
ts[0].insert(n);
15+
ts[1].insert(n);
16+
queue<int> q{{p}};
17+
while (!q.empty()) {
18+
int i = q.front();
19+
q.pop();
20+
int mi = max(i - k + 1, k - i - 1);
21+
int mx = min(i + k - 1, n * 2 - k - i - 1);
22+
auto& s = ts[mi % 2];
23+
auto it = s.lower_bound(mi);
24+
while (*it <= mx) {
25+
int j = *it;
26+
ans[j] = ans[i] + 1;
27+
q.push(j);
28+
it = s.erase(it);
29+
}
30+
}
31+
return ans;
32+
}
33+
};

0 commit comments

Comments
 (0)