You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We just copy the element from the original array to the new array, and if we found the zero, we duplicate it.
5
5
```kotlin
6
6
funduplicateZeros(arr:IntArray) {
@@ -43,6 +43,11 @@ fun duplicateZeros(arr: IntArray): Unit {
43
43
var write = n -1+ zeros
44
44
for (read in n -1 downTo 0) {
45
45
if (arr[read] ==0) {
46
+
// Pitfall: We need to check one by one, not just write -= 2, see below.
47
+
// if (write >= n) {
48
+
// // Wrong, we will skip checking at the index `write - 1`
49
+
// write -= 2
50
+
// }
46
51
repeat(2) {
47
52
if (write >= n) {
48
53
write--
@@ -53,13 +58,25 @@ fun duplicateZeros(arr: IntArray): Unit {
53
58
} else {
54
59
if (write >= n) {
55
60
write--
56
-
continue
61
+
} else {
62
+
arr[write] = arr[read]
63
+
write--
57
64
}
58
-
arr[write--] = arr[read]
59
65
}
60
66
}
61
67
}
62
68
```
63
69
64
70
***Time Complexity**: `O(n)`.
65
-
***Space Complexity**: `O(1)`, it's just in-place copy, no extra space required.
71
+
***Space Complexity**: `O(1)`, it's just in-place copy, no extra space required.
72
+
73
+
The pitfall I made is that I didn't check the index `write` one by one, so I missed the checking at the index `write - 1`:
74
+
75
+
```js
76
+
n-1, n, n+1
77
+
..., X], 0
78
+
r
79
+
w-2 w
80
+
```
81
+
82
+
If we just `write -= 2` when `arr[read] == 0` and `write` is at index `n` (out of bounds), we will miss updateing the element `X` at the index `n - 1`. Check the example `[8,4,5,0,0,0,0,7]`.
Copy file name to clipboardExpand all lines: leetcode/1234.replace-the-substring-for-balanced-string.md
+24-13Lines changed: 24 additions & 13 deletions
Original file line number
Diff line number
Diff line change
@@ -1,29 +1,41 @@
1
1
# [1234. Replace the Substring for Balanced String](https://leetcode.com/problems/replace-the-substring-for-balanced-string/description/)
2
2
3
+
## Test Cases
4
+
### Edge / Corner Cases
5
+
* The string is already balanced.
6
+
* The string contains only single type of characters.
7
+
3
8
## Binary Search + Sliding Window
4
-
We're looking for a substring (window) which we can replace to make the string balanced.
9
+
We're looking for a substring (window) which we can replace any characters within the window to make the string balanced.
5
10
```js
6
11
QQQQWWWWWEEERRR
7
-
...|-----|...
12
+
^^^^|-----|^^^^
13
+
// We focus on the outside of the window, we can replace the chars in the window to make the string balanced.
8
14
```
9
15
10
-
**Idea!!** For a given window, we should count the chars outside the window, and if there is any missing chars, we can always replace the chars in the window to make the string balanced, that is a valid window.
16
+
**Idea!!** For a given window, we should count the chars outside the window, and if there is any missing chars (`count[char] <= n / 4`), we can always replace the chars in the window to make the string balanced, that is a valid window.
11
17
12
-
If there are some redundant chars, it's impossible to replace in the window, the window is invalid.
18
+
If there are chars that is more than `n / 4`, it's impossible to replace in the window, the window is invalid.
13
19
14
-
Based on this observation, the window chould be range in `0 .. n-1`, we can check if the window is valid (all the counts of each chars <= `n/4`) or not (any of the count of char > `n/4`). It's a fixed search space and monotonic, we can use binary search to find the smallest window.
20
+
Based on this observation, the window chould be range in `0 .. n - 1`, we can check if the window is valid (all the counts of each chars <= `n / 4`) or not. As the window size increases, the outside of the window is smaller, it's more likely to satisfy the condition. (all the counts of each chars <= `n / 4`), and vice versa. Since it's a fixed search space and monotonic, we can use binary search to find the smallest window.
21
+
22
+
```js
23
+
window=01234... n -1
24
+
valid =XXXOO...O
25
+
^// The smallest window
26
+
```
15
27
16
28
---
17
29
```markdown
18
30
我們要找某個最小區間,這區間之內可以補足任意的字母,使得整個字串變平衡。
19
31
20
-
那麼我們可以看區間外面的字母,少哪一個我都可以在這區間補足。
32
+
那麼我們可以**看區間外面的字母,少哪一個我都可以在這區間補足。**
21
33
然而,如果區間外面的某個字母太多了,那麼在這區間也不能補足或減少,這區間就變成無效。
22
34
23
-
所以回到題目,長度 n 的字串,我們定一個區間,我們要看區間「外」的所有字母是否都 <= `n/4`:
24
-
* `count[x] < n/4`: 可以在區間補齊。
25
-
* `count[x] = n/4`: 合法,也不做任何事。
26
-
* `count[x] > n/4`: 區間也不能修正,此區間無效。
35
+
所以回到題目,長度 n 的字串,我們定一個區間,我們要看區間「外」的所有字母是否都 <= `n / 4`:
Copy file name to clipboardExpand all lines: leetcode/1574.shortest-subarray-to-be-removed-to-make-array-sorted.md
+38-17Lines changed: 38 additions & 17 deletions
Original file line number
Diff line number
Diff line change
@@ -1,18 +1,33 @@
1
1
# [1574. Shortest Subarray to be Removed to Make Array Sorted](https://leetcode.com/problems/shortest-subarray-to-be-removed-to-make-array-sorted/description/)
2
2
3
+
## Test Cases
4
+
### Edge / Corner Cases
5
+
* The array is already sorted. (Important to check this condition)
6
+
```
7
+
Input: [1, 2, 3]
8
+
Output: 0
9
+
```
10
+
* The array is in descending order.
11
+
```
12
+
Input: [3, 2, 1]
13
+
Output: 2
14
+
```
15
+
3
16
## Prework
4
17
For a given array, we can breakdown into three parts:
5
18
```js
6
19
[XXXX] [YYYY] [ZZZZ]
7
20
0 i j n-1
8
21
```
22
+
23
+
To make the whole array sorted by removing `Y` part (may be empty), we have to satisfy the following conditions:
9
24
1.`[0:i]` is non-decreasing.
10
25
2.`[j:n-1]` is non-decreasing.
11
26
3.`arr[i] <= arr[j]`.
12
27
13
-
For the example input `[1, 2, 3, 9, 4, 2, 3, 5]`, we can find the two non-decreasing subarrays (for 1. and 2. above):
14
-
* Find the longest non-decreasing subarray from the beginning.
15
-
* Find the longest non-decreasing subarray from the end.
28
+
So the first steps is to identify the longest non-decreasing subarrays from the beginning and the end of the array. (for the conditions 1. and 2. above)
29
+
30
+
For the example input `[1, 2, 3, 9, 4, 2, 3, 5]`, we can identify the two non-decreasing subarrays from the beginning and the end of the array:
16
31
17
32
```js
18
33
[1, 2, 3, 9, 4, 2, 3, 5]
@@ -24,7 +39,7 @@ For the example input `[1, 2, 3, 9, 4, 2, 3, 5]`, we can find the two non-decrea
24
39
R
25
40
```
26
41
27
-
After finding the longest non-decreasing subarray from the beginning and the end, there are 3 options to consider:
42
+
After identifying the longest non-decreasing subarray from the beginning and the end, there are 3 options to consider as the result:
28
43
1. We remove the left part: `[X, X, X, X, X, 2, 3, 5]`
29
44
2. We remove the right part: `[1, 2, 3, 9, X, X, X, X]`
30
45
3. We remove the middle part and merge the two non-decreasing subarrays into one: `[1, 2, 3, 9, 2, 3, 5]`
@@ -39,17 +54,17 @@ fun findLengthOfShortestSubarray(arr: IntArray): Int {
39
54
// Find the longest non-decreasing subarray from the beginning
40
55
while (left +1< n && arr[left] <= arr[left +1]) left++
41
56
42
-
// All are non-decreasing
57
+
// All are non-decreasing (it's necessary to check this condition)
43
58
if (left == n -1) return0
44
59
45
60
// Find the longest non-decreasing subarray from the end
46
61
var right = n -1
47
-
while (0< right -1&& arr[right -1] <= arr[right]) right--
62
+
while (0<= right -1&& arr[right -1] <= arr[right]) right--
48
63
49
64
// Remove left part or right part
50
65
var result = minOf(n - left -1, right)
51
66
52
-
// TODO: See below...
67
+
// TODO: Not finished, see below...
53
68
}
54
69
```
55
70
@@ -64,34 +79,39 @@ How to move the pointers `L` and `R`?
64
79
> Very nice illustration to explain how to move the pointers `L` and `R`: https://leetcode.cn/problems/shortest-subarray-to-be-removed-to-make-array-sorted/solutions/2189149/dong-hua-yi-xie-jiu-cuo-liang-chong-xie-iijwz/
65
80
66
81
## Two Pointers + Binary Search
67
-
The first approach is to iterate all possible `l` in `0..L`, then find the first `r` in `R..n-1` that satisfies `arr[l] <= arr[r]`:
82
+
Since the `R..n-1` is non-decreasing (sorted), so we can iterate all possible `l` in `0..L`, then binary search the first `r` in `R..n-1` that satisfies `arr[l] <= arr[r]` (keep sorted after merge):
83
+
84
+
```js
85
+
[0, ...L], ..., [R, ... n-1]
86
+
l -> r ->
87
+
```
68
88
69
89
```js
70
90
01234567// index
71
91
1, 2, 3, 9, 2, 3, 5// value
72
92
LR// the original non-decreasing subarrays
93
+
|--------||--------|
73
94
l r // l = 0 -> r = 4, to remove is 3 (2, 3, 9)
74
95
l r // l = 1 -> r = 4, to remove is 2 (3, 9)
75
96
l r // l = 2 -> r = 5, to remove is 1 (9, 2)
76
97
l r // r is out of range, to remove is 3 (2, 3, 5)
77
98
```
78
99
79
-
Because `R..n-1` are non-decreasing (sorted), we can use binary search to find the first `r` that satisfies `arr[l] <= arr[r]`, then update the minimum result.
80
-
81
100
```kotlin
82
101
funfindLengthOfShortestSubarray(arr:IntArray): Int {
83
102
// ... see above
84
103
85
104
for (l in0..left) {
86
-
val r = search(arr, arr[l], right, n -1)
87
-
result = minOf(result, r - l -1)
105
+
// right is monotonic increasing, so we don't start from original right index
106
+
right = search(arr, arr[l], right)
107
+
result = minOf(result, right - l -1)
88
108
}
89
109
return result
90
110
}
91
111
92
-
privatefunsearch(arr:IntArray, target:Int, start:Int, end:Int): Int {
93
-
var left =start
94
-
var right =end
112
+
privatefunsearch(arr:IntArray, target:Int, startIndex:Int): Int {
113
+
var left =startIndex
114
+
var right =arr.size -1
95
115
while (left <= right) {
96
116
val middle = left + (right - left) /2
97
117
if (target <= arr[middle]) {
@@ -108,13 +128,14 @@ private fun search(arr: IntArray, target: Int, start: Int, end: Int): Int {
108
128
***Space Complexity:**`O(1)`
109
129
110
130
## Two Pointers
111
-
We can optimize the above solution based on the same idea by using two pointers approach.
131
+
We can optimize the above solution based on the same idea (to find the first `r` that satisfies `arr[l] <= arr[r]`) by using two pointers approach.
112
132
113
133
Because `0..L` and `R..n-1` are both non-decreasing, as we find the first `r` that satisfies `arr[l] <= arr[r]` in the first iteration, then we can start from the previous `r` to find the next `r` that satisfies `arr[l] <= arr[r]`, we don't need to start from `R` again.
114
134
115
135
```js
116
136
1, 3, 8, 9, 2, 3, 5, 6, 7, 8
117
137
LR
138
+
|--------||--------------|
118
139
l r1 // first iteration
119
140
l ->r2 // second iteration, r starts from the previous r
120
141
l r2 -------> r3 // third iteration
@@ -158,7 +179,7 @@ fun findLengthOfShortestSubarray(arr: IntArray): Int {
158
179
if (left == n -1) return0
159
180
160
181
var right = n -1
161
-
while (0< right -1&& arr[right -1] <= arr[right]) right--
182
+
while (0<= right -1&& arr[right -1] <= arr[right]) right--
Copy file name to clipboardExpand all lines: leetcode/1775.equal-sum-arrays-with-minimum-number-of-operations.md
+12-13Lines changed: 12 additions & 13 deletions
Original file line number
Diff line number
Diff line change
@@ -1,21 +1,23 @@
1
1
# [1775. Equal Sum Arrays With Minimum Number of Operations](https://leetcode.com/problems/equal-sum-arrays-with-minimum-number-of-operations/description/)
2
2
3
-
## Greedy
4
-
**Idea!** To make the two sum's equal with the minimum nubmer of operation, we need either to increase to `6` in the smaller sum array or decrease to `1` in the larger sum array. If we change all elements to `6` and its sum is still less than another array or change all elements to `1` and its sum is still larger than another array, it's impossible to make the two sums equal.
3
+
## Greedy + Two Pointers
4
+
**Idea!** To make the two sum's equal with the minimum nubmer of operation, we should maximize the increase of the smaller sum array or minimize the decrease of the larger sum array.
5
+
6
+
We need either to increase to `6` in the smaller sum array or decrease to `1` in the larger sum array greedily. If we change all elements to `6` and its sum is still less than another array or change all elements to `1` and its sum is still larger than another array, it's impossible to make the two sums equal.
5
7
6
8
> Intuitions: We want to minimize the number of operations. So we pick 1 from the smaller array and change it to 6. Or, we pick 6 from the larger array and change it to 1. That's the fastest way to converge two sums.
7
9
>
8
10
> 最少操作数的本质是:和小的数组里面每个数尽量变为 6;和大的数组里面的每个数尽量缩小为 1
9
11
10
-
Based on the above idea and suppose `sum(A) > sum(B)`, we can change the largest element in `A` to `1` to decrease `sum(A)`, or change the smallest number in `B` to `6` to increase `sum(B)` (if we still have number to chnage). We can repeat this process until `sum(A) <= sum(B)` or we have no number to change.
12
+
Based on the above idea and suppose `sum(A) > sum(B)`, we can change the largest element in `A` to `1` to decrease `sum(A)`, or change the smallest number in `B` to `6` to increase `sum(B)` (if we still have numbers to change). We can repeat this process until `sum(A) <= sum(B)` or we have no number to change (return `-1`).
11
13
12
14
```js
13
15
-------|--------------------|--------
14
-
sum(B) sum(A)
15
-
-->// Increase sum(B) by changing the smallest number in B to 6
16
-
<--// Decrease sum(A) by changing the largest number in A to 1
17
-
|<-->|
18
-
sum(A) <=sum(B) // Until sum(A) <= sum(B) or we have no number to change
16
+
sum(B) <sum(A)
17
+
-->|// Increase sum(B) by changing the smallest number in B to 6
18
+
|<--// Decrease sum(A) by changing the largest number in A to 1
19
+
sum(A) <=sum(B) // Until sum(A) <= sum(B) or we have no number to change
20
+
|<---->|
19
21
```
20
22
21
23
Our greedy stragety is to change the largest number in `A` to `1` or the smallest number in `B` to `6` at each step. And we also choose the larger difference of change between `A` and `B` to change or either if they are equal.
@@ -36,10 +38,7 @@ B = [1, ...]
36
38
37
39
We repeat this process until `sum(A) <= sum(B)` or we have no number to change. The number of operations is the number of steps we take.
38
40
39
-
Why `sum(A) < sum(B)` works? Because we can always change the largest number in `A` to `1` or the smallest number in `B` to `6` to make `sum(A) <= sum(B)`, when `sum(A)` becomes less than `sum(B)`, we can increase or decrease some numbers that we have changed before to make `sum(A) == sum(B)`.
40
-
41
-
> If target diff < 0, we can always make target diff == 0 by reverting some numbers from 6 to the less number or 1 to greater number.
42
-
41
+
Why `sum(A) < sum(B)` is valid? It's over-adjusted, we can revert some numbers that we have changed before to make `sum(A) == sum(B)`. If target diff < 0, we can always make target diff == 0 by reverting some numbers from 6 to the less number or 1 to greater number, see the following example:
43
42
44
43
```js
45
44
A= [6, 6] =12
@@ -97,7 +96,7 @@ fun minOperations(nums1: IntArray, nums2: IntArray): Int {
97
96
} elseif (p2 < n) { // We still have B, but A is out of bound
98
97
sum2 += (6- nums2[p2])
99
98
p2++
100
-
} else { // There is no any number to change
99
+
} else { // There is no any number to change but the sum1 > sum2
0 commit comments