Skip to content

Commit 23b766d

Browse files
authored
feat: add solutions to lc problem: No.3048 (#2479)
No.3048.Earliest Second to Mark Indices I
1 parent 6465b9b commit 23b766d

File tree

7 files changed

+456
-88
lines changed

7 files changed

+456
-88
lines changed

solution/3000-3099/3048.Earliest Second to Mark Indices I/README.md

+156-30
Original file line numberDiff line numberDiff line change
@@ -82,68 +82,194 @@
8282

8383
## 解法
8484

85-
### 方法一
85+
### 方法一:二分查找
86+
87+
我们注意到,如果我们能够在 $t$ 秒内标记所有下标,那么我们也能在 $t' \geq t$ 秒内标记所有下标。因此,我们可以使用二分查找的方法找到最早的秒数。
88+
89+
我们定义二分查找的左右边界分别为 $l = 1$ 和 $r = m + 1$,其中 $m$ 是数组 `changeIndices` 的长度。对于每一个 $t = \frac{l + r}{2}$,我们检查是否能在 $t$ 秒内标记所有下标。如果能,我们将右边界移动到 $t$,否则我们将左边界移动到 $t + 1$。最终,我们判定左边界是否大于 $m$,如果是则返回 $-1$,否则返回左边界。
90+
91+
题目的关键在于如何判断是否能在 $t$ 秒内标记所有下标。我们可以使用一个数组 $last$ 记录每一个下标最晚需要被标记的时间,用一个变量 $decrement$ 记录当前可以减少的次数,用一个变量 $marked$ 记录已经被标记的下标的数量。
92+
93+
我们遍历数组 `changeIndices` 的前 $t$ 个元素,对于每一个元素 $i$,如果 $last[i] = s$,那么我们需要检查 $decrement$ 是否大于等于 $nums[i - 1]$,如果是,我们将 $decrement$ 减去 $nums[i - 1]$,并且将 $marked$ 加一;否则,我们返回 `False`。如果 $last[i] \neq s$,那么我们可以暂时不标记下标,因此将 $decrement$ 加一。最后,我们检查 $marked$ 是否等于 $n$,如果是,我们返回 `True`,否则返回 `False`
94+
95+
时间复杂度 $O(m \times \log m)$,空间复杂度 $O(n)$。其中 $n$ 和 $m$ 分别是数组 `nums``changeIndices` 的长度。
8696

8797
<!-- tabs:start -->
8898

8999
```python
90-
100+
class Solution:
101+
def earliestSecondToMarkIndices(
102+
self, nums: List[int], changeIndices: List[int]
103+
) -> int:
104+
def check(t: int) -> bool:
105+
decrement = 0
106+
marked = 0
107+
last = {i: s for s, i in enumerate(changeIndices[:t])}
108+
for s, i in enumerate(changeIndices[:t]):
109+
if last[i] == s:
110+
if decrement < nums[i - 1]:
111+
return False
112+
decrement -= nums[i - 1]
113+
marked += 1
114+
else:
115+
decrement += 1
116+
return marked == len(nums)
117+
118+
m = len(changeIndices)
119+
l = bisect_left(range(1, m + 2), True, key=check) + 1
120+
return -1 if l > m else l
91121
```
92122

93123
```java
94124
class Solution {
125+
private int[] nums;
126+
private int[] changeIndices;
127+
95128
public int earliestSecondToMarkIndices(int[] nums, int[] changeIndices) {
96-
int l = 0;
97-
int r = changeIndices.length + 1;
129+
this.nums = nums;
130+
this.changeIndices = changeIndices;
131+
int m = changeIndices.length;
132+
int l = 1, r = m + 1;
98133
while (l < r) {
99-
final int m = (l + r) / 2;
100-
if (canMark(nums, changeIndices, m)) {
101-
r = m;
134+
int mid = (l + r) >> 1;
135+
if (check(mid)) {
136+
r = mid;
102137
} else {
103-
l = m + 1;
138+
l = mid + 1;
104139
}
105140
}
106-
return l <= changeIndices.length ? l : -1;
141+
return l > m ? -1 : l;
107142
}
108143

109-
private boolean canMark(int[] nums, int[] changeIndices, int second) {
110-
int numMarked = 0;
111-
int decrement = 0;
112-
// indexToLastSecond[i] := the last second to mark the index i
113-
int[] indexToLastSecond = new int[nums.length];
114-
Arrays.fill(indexToLastSecond, -1);
115-
116-
for (int i = 0; i < second; ++i) {
117-
indexToLastSecond[changeIndices[i] - 1] = i;
144+
private boolean check(int t) {
145+
int[] last = new int[nums.length + 1];
146+
for (int s = 0; s < t; ++s) {
147+
last[changeIndices[s]] = s;
118148
}
119-
120-
for (int i = 0; i < second; ++i) {
121-
// Convert to 0-indexed.
122-
final int index = changeIndices[i] - 1;
123-
if (i == indexToLastSecond[index]) {
124-
// Reach the last occurrence of the number.
125-
// So, the current second will be used to mark the index.
126-
if (nums[index] > decrement) {
127-
// The decrement is less than the number to be marked.
149+
int decrement = 0;
150+
int marked = 0;
151+
for (int s = 0; s < t; ++s) {
152+
int i = changeIndices[s];
153+
if (last[i] == s) {
154+
if (decrement < nums[i - 1]) {
128155
return false;
129156
}
130-
decrement -= nums[index];
131-
++numMarked;
157+
decrement -= nums[i - 1];
158+
++marked;
132159
} else {
133160
++decrement;
134161
}
135162
}
136-
return numMarked == nums.length;
163+
return marked == nums.length;
137164
}
138165
}
139166
```
140167

141168
```cpp
169+
class Solution {
170+
public:
171+
int earliestSecondToMarkIndices(vector<int>& nums, vector<int>& changeIndices) {
172+
int n = nums.size();
173+
int last[n + 1];
174+
auto check = [&](int t) {
175+
memset(last, 0, sizeof(last));
176+
for (int s = 0; s < t; ++s) {
177+
last[changeIndices[s]] = s;
178+
}
179+
int decrement = 0, marked = 0;
180+
for (int s = 0; s < t; ++s) {
181+
int i = changeIndices[s];
182+
if (last[i] == s) {
183+
if (decrement < nums[i - 1]) {
184+
return false;
185+
}
186+
decrement -= nums[i - 1];
187+
++marked;
188+
} else {
189+
++decrement;
190+
}
191+
}
192+
return marked == n;
193+
};
142194

195+
int m = changeIndices.size();
196+
int l = 1, r = m + 1;
197+
while (l < r) {
198+
int mid = (l + r) >> 1;
199+
if (check(mid)) {
200+
r = mid;
201+
} else {
202+
l = mid + 1;
203+
}
204+
}
205+
return l > m ? -1 : l;
206+
}
207+
};
143208
```
144209

145210
```go
211+
func earliestSecondToMarkIndices(nums []int, changeIndices []int) int {
212+
n, m := len(nums), len(changeIndices)
213+
l := sort.Search(m+1, func(t int) bool {
214+
last := make([]int, n+1)
215+
for s, i := range changeIndices[:t] {
216+
last[i] = s
217+
}
218+
decrement, marked := 0, 0
219+
for s, i := range changeIndices[:t] {
220+
if last[i] == s {
221+
if decrement < nums[i-1] {
222+
return false
223+
}
224+
decrement -= nums[i-1]
225+
marked++
226+
} else {
227+
decrement++
228+
}
229+
}
230+
return marked == n
231+
})
232+
if l > m {
233+
return -1
234+
}
235+
return l
236+
}
237+
```
146238

239+
```ts
240+
function earliestSecondToMarkIndices(nums: number[], changeIndices: number[]): number {
241+
const [n, m] = [nums.length, changeIndices.length];
242+
let [l, r] = [1, m + 1];
243+
const check = (t: number): boolean => {
244+
const last: number[] = Array(n + 1).fill(0);
245+
for (let s = 0; s < t; ++s) {
246+
last[changeIndices[s]] = s;
247+
}
248+
let [decrement, marked] = [0, 0];
249+
for (let s = 0; s < t; ++s) {
250+
const i = changeIndices[s];
251+
if (last[i] === s) {
252+
if (decrement < nums[i - 1]) {
253+
return false;
254+
}
255+
decrement -= nums[i - 1];
256+
++marked;
257+
} else {
258+
++decrement;
259+
}
260+
}
261+
return marked === n;
262+
};
263+
while (l < r) {
264+
const mid = (l + r) >> 1;
265+
if (check(mid)) {
266+
r = mid;
267+
} else {
268+
l = mid + 1;
269+
}
270+
}
271+
return l > m ? -1 : l;
272+
}
147273
```
148274

149275
<!-- tabs:end -->

0 commit comments

Comments
 (0)