@@ -93,32 +93,313 @@ tags:
9393
9494<!-- solution:start -->
9595
96- ### 方法一
96+ ### 方法一:BFS + 有序集合
97+
98+ 我们记字符串 $s$ 的长度为 $n$,记当前字符串中 '0' 的数量为 $\textit{cur}$,每一次操作,我们选择其中 $k$ 个下标进行翻转,其中有 $x$ 个下标从 '0' 翻转为 '1',有 $k-x$ 个下标从 '1' 翻转为 '0',则翻转后字符串中 '0' 的数量为 $\textit{cur} + k - 2x$。
99+
100+ 而 $x$ 的取值需要满足以下条件:
101+
102+ 1 . 最多取 $\min(\textit{cur}, k)$ 个 '0',因为我们不能翻转超过 $\textit{cur}$ 个 '0',那么 $0 \leq x \leq \min(\textit{cur}, k)$。
103+ 2 . 最多取 $n - \textit{cur}$ 个 '1',因为我们不能翻转超过 $n - \textit{cur}$ 个 '1',那么 $k - x \leq n - \textit{cur}$,即 $x \geq k - n + \textit{cur}$。
104+
105+ 因此 $x$ 的取值范围为 $[ \max(k - n + \textit{cur}, 0), \min(\textit{cur}, k)] $,翻转后字符串中 '0' 的数量的取值范围为 $[ \textit{cur} + k - 2 \cdot \min(\textit{cur}, k), \textit{cur} + k - 2 \cdot \max(k - n + \textit{cur}, 0)] $。
106+
107+ 我们注意到,翻转后字符串中 '0' 的数量的奇偶性与翻转前字符串中 '0' 的数量的奇偶性相同。因此,我们可以使用两个有序集合分别存储 '0' 的数量为偶数和奇数的状态。
108+
109+ 我们使用 BFS 来搜索状态转移图,初始状态为字符串中 '0' 的数量,目标状态为 0。每次从队列中取出一个状态 $\textit{cur}$,计算翻转后字符串中 '0' 的数量的取值范围 $[ l, r] $,在有序集合中找到所有在 $[ l, r] $ 范围内的状态,并将它们加入队列,同时从有序集合中删除它们。
110+
111+ 如果我们在 BFS 过程中访问到了状态 0,则返回当前的操作次数;如果 BFS 结束后仍未访问到状态 0,则返回 -1。
112+
113+ 时间复杂度 $O(n \log n)$,空间复杂度 $O(n)$。其中 $O(n)$ 是 BFS 过程中可能访问的状态数量,而 $O(\log n)$ 是在有序集合中插入和删除元素的时间复杂度。
97114
98115<!-- tabs:start -->
99116
100117#### Python3
101118
102119``` python
103-
120+ class Solution :
121+ def minOperations (self , s : str , k : int ) -> int :
122+ n = len (s)
123+ ts = [SortedSet() for _ in range (2 )]
124+ for i in range (n + 1 ):
125+ ts[i % 2 ].add(i)
126+ cnt0 = s.count(' 0' )
127+ ts[cnt0 % 2 ].remove(cnt0)
128+ q = deque([cnt0])
129+ ans = 0
130+ while q:
131+ for _ in range (len (q)):
132+ cur = q.popleft()
133+ if cur == 0 :
134+ return ans
135+ l = cur + k - 2 * min (cur, k)
136+ r = cur + k - 2 * max (k - n + cur, 0 )
137+ t = ts[l % 2 ]
138+ j = t.bisect_left(l)
139+ while j < len (t) and t[j] <= r:
140+ q.append(t[j])
141+ t.remove(t[j])
142+ ans += 1
143+ return - 1
104144```
105145
106146#### Java
107147
108148``` java
109-
149+ class Solution {
150+ public int minOperations (String s , int k ) {
151+ int n = s. length();
152+
153+ TreeSet<Integer > [] ts = new TreeSet [2 ];
154+ Arrays . setAll(ts, i - > new TreeSet<> ());
155+
156+ for (int i = 0 ; i <= n; i++ ) {
157+ ts[i % 2 ]. add(i);
158+ }
159+
160+ int cnt0 = 0 ;
161+ for (char c : s. toCharArray()) {
162+ if (c == ' 0' ) {
163+ cnt0++ ;
164+ }
165+ }
166+
167+ ts[cnt0 % 2 ]. remove(cnt0);
168+
169+ Deque<Integer > q = new ArrayDeque<> ();
170+ q. offer(cnt0);
171+
172+ int ans = 0 ;
173+ while (! q. isEmpty()) {
174+ for (int size = q. size(); size > 0 ; -- size) {
175+ int cur = q. poll();
176+ if (cur == 0 ) {
177+ return ans;
178+ }
179+
180+ int l = cur + k - 2 * Math . min(cur, k);
181+ int r = cur + k - 2 * Math . max(k - n + cur, 0 );
182+
183+ TreeSet<Integer > t = ts[l % 2 ];
184+
185+ Integer next = t. ceiling(l);
186+ while (next != null && next <= r) {
187+ q. offer(next);
188+ t. remove(next);
189+ next = t. ceiling(l);
190+ }
191+ }
192+ ans++ ;
193+ }
194+
195+ return - 1 ;
196+ }
197+ }
110198```
111199
112200#### C++
113201
114202``` cpp
115-
203+ class Solution {
204+ public:
205+ int minOperations(string s, int k) {
206+ int n = s.size();
207+
208+ set<int> ts[2];
209+ for (int i = 0; i <= n; i++) {
210+ ts[i % 2].insert(i);
211+ }
212+
213+ int cnt0 = count(s.begin(), s.end(), ' 0' );
214+ ts[cnt0 % 2 ].erase(cnt0);
215+
216+ queue<int > q;
217+ q.push(cnt0);
218+
219+ int ans = 0 ;
220+
221+ while (!q.empty()) {
222+ for (int size = q.size(); size > 0; --size) {
223+ int cur = q.front();
224+ q.pop();
225+ if (cur == 0) {
226+ return ans;
227+ }
228+
229+ int l = cur + k - 2 * min(cur, k);
230+ int r = cur + k - 2 * max(k - n + cur, 0);
231+
232+ auto& t = ts[l % 2];
233+ auto it = t.lower_bound(l);
234+
235+ while (it != t.end() && *it <= r) {
236+ q.push(*it);
237+ it = t.erase(it);
238+ }
239+ }
240+ ans++;
241+ }
242+
243+ return -1;
244+ }
245+ };
116246```
117247
118248#### Go
119249
120250``` go
251+ func minOperations (s string , k int ) int {
252+ n := len (s)
253+
254+ ts := [2 ]*redblacktree.Tree {
255+ redblacktree.NewWithIntComparator (),
256+ redblacktree.NewWithIntComparator (),
257+ }
258+
259+ for i := 0 ; i <= n; i++ {
260+ ts[i%2 ].Put (i, struct {}{})
261+ }
262+
263+ cnt0 := strings.Count (s, " 0" )
264+ ts[cnt0%2 ].Remove (cnt0)
265+
266+ q := []int {cnt0}
267+ ans := 0
268+
269+ for len (q) > 0 {
270+ nq := []int {}
271+
272+ for _ , cur := range q {
273+ if cur == 0 {
274+ return ans
275+ }
276+
277+ l := cur + k - 2 *min (cur, k)
278+ r := cur + k - 2 *max (k-n+cur, 0 )
279+ t := ts[l%2 ]
280+
281+ node , found := t.Ceiling (l)
282+ for found && node.Key .(int ) <= r {
283+ val := node.Key .(int )
284+ nq = append (nq, val)
285+ t.Remove (val)
286+ node, found = t.Ceiling (l)
287+ }
288+ }
289+
290+ q = nq
291+ ans++
292+ }
293+
294+ return -1
295+ }
296+ ```
297+
298+ #### TypeScript
299+
300+ ``` ts
301+ import { AvlTree } from ' @datastructures-js/binary-search-tree' ;
302+
303+ function minOperations(s : string , k : number ): number {
304+ const n: number = s .length ;
305+
306+ const ts = [new AvlTree <number >(), new AvlTree <number >()];
307+
308+ for (let i = 0 ; i <= n ; i ++ ) {
309+ ts [i % 2 ].insert (i );
310+ }
311+
312+ let cnt0 = 0 ;
313+ for (const c of s ) {
314+ if (c === ' 0' ) cnt0 ++ ;
315+ }
316+
317+ ts [cnt0 % 2 ].remove (cnt0 );
318+
319+ let q: number [] = [cnt0 ];
320+ let ans = 0 ;
321+
322+ while (q .length > 0 ) {
323+ const nq: number [] = [];
324+
325+ for (const cur of q ) {
326+ if (cur === 0 ) {
327+ return ans ;
328+ }
329+
330+ const l = cur + k - 2 * Math .min (cur , k );
331+ const r = cur + k - 2 * Math .max (k - n + cur , 0 );
332+
333+ const t = ts [l % 2 ];
334+ let node = t .upperBound (l , true );
335+ while (node && node .getValue () <= r ) {
336+ const val = node .getValue ();
337+ nq .push (val );
338+ t .remove (val );
339+ node = t .upperBound (l , false );
340+ }
341+ }
342+
343+ q = nq ;
344+ ans ++ ;
345+ }
346+
347+ return - 1 ;
348+ }
349+ ```
350+
351+ #### Rust
352+
353+ ``` rust
354+ use std :: collections :: {BTreeSet , VecDeque };
355+
356+ impl Solution {
357+ pub fn min_operations (s : String , k : i32 ) -> i32 {
358+ let n : i32 = s . len () as i32 ;
359+ let k : i32 = k ;
360+
361+ let mut ts : [BTreeSet <i32 >; 2 ] = [BTreeSet :: new (), BTreeSet :: new ()];
362+ for i in 0 ..= n {
363+ ts [(i % 2 ) as usize ]. insert (i );
364+ }
365+
366+ let cnt0 : i32 = s . bytes (). filter (| & c | c == b '0' ). count () as i32 ;
367+ ts [(cnt0 % 2 ) as usize ]. remove (& cnt0 );
368+
369+ let mut q : VecDeque <i32 > = VecDeque :: new ();
370+ q . push_back (cnt0 );
371+
372+ let mut ans : i32 = 0 ;
373+
374+ while ! q . is_empty () {
375+ let size = q . len ();
376+ for _ in 0 .. size {
377+ let cur = q . pop_front (). unwrap ();
378+ if cur == 0 {
379+ return ans ;
380+ }
381+
382+ let l = cur + k - 2 * cur . min (k );
383+ let r = cur + k - 2 * (k - n + cur ). max (0 );
384+
385+ let parity = (l % 2 ) as usize ;
386+
387+ let vals : Vec <i32 > = ts [parity ]
388+ . range (l ..= r )
389+ . cloned ()
390+ . collect ();
391+
392+ for v in vals {
393+ q . push_back (v );
394+ ts [parity ]. remove (& v );
395+ }
396+ }
397+ ans += 1 ;
398+ }
121399
400+ - 1
401+ }
402+ }
122403```
123404
124405<!-- tabs:end -->
0 commit comments