题目描述
给你一个数组 arr
,该数组表示一个从 1
到 n
的数字排列。有一个长度为 n
的二进制字符串,该字符串上的所有位最初都设置为 0
。
在从 1
到 n
的每个步骤 i
中(假设二进制字符串和 arr
都是从 1
开始索引的情况下),二进制字符串上位于位置 arr[i]
的位将会设为 1
。
给你一个整数 m
,请你找出二进制字符串上存在长度为 m
的一组 1
的最后步骤。一组 1
是一个连续的、由 1
组成的子串,且左右两边不再有可以延伸的 1
。
返回存在长度 恰好 为 m
的 一组 1
的最后步骤。如果不存在这样的步骤,请返回 -1
。
示例 1:
输入:arr = [3,5,1,2,4], m = 1
输出:4
解释:
步骤 1:"00100",由 1 构成的组:["1"]
步骤 2:"00101",由 1 构成的组:["1", "1"]
步骤 3:"10101",由 1 构成的组:["1", "1", "1"]
步骤 4:"11101",由 1 构成的组:["111", "1"]
步骤 5:"11111",由 1 构成的组:["11111"]
存在长度为 1 的一组 1 的最后步骤是步骤 4 。
示例 2:
输入:arr = [3,1,5,4,2], m = 2
输出:-1
解释:
步骤 1:"00100",由 1 构成的组:["1"]
步骤 2:"10100",由 1 构成的组:["1", "1"]
步骤 3:"10101",由 1 构成的组:["1", "1", "1"]
步骤 4:"10111",由 1 构成的组:["1", "111"]
步骤 5:"11111",由 1 构成的组:["11111"]
不管是哪一步骤都无法形成长度为 2 的一组 1 。
示例 3:
输入:arr = [1], m = 1
输出:1
示例 4:
输入:arr = [2,1], m = 2
输出:2
提示:
n == arr.length
1 <= n <= 10^5
1 <= arr[i] <= n
arr
中的所有整数 互不相同
1 <= m <= arr.length
解法
方法一:并查集
正向遍历 $arr$,利用并查集动态维护每组 $1$ 的长度。
时间复杂度 $O(n \times \log n)$。
相似题目:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 | class Solution:
def findLatestStep(self, arr: List[int], m: int) -> int:
def find(x):
if p[x] != x:
p[x] = find(p[x])
return p[x]
def union(a, b):
pa, pb = find(a), find(b)
if pa == pb:
return
p[pa] = pb
size[pb] += size[pa]
n = len(arr)
if m == n:
return n
vis = [False] * n
p = list(range(n))
size = [1] * n
ans = -1
for i, v in enumerate(arr):
v -= 1
if v and vis[v - 1]:
if size[find(v - 1)] == m:
ans = i
union(v, v - 1)
if v < n - 1 and vis[v + 1]:
if size[find(v + 1)] == m:
ans = i
union(v, v + 1)
vis[v] = True
return ans
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 | class Solution {
private int[] p;
private int[] size;
public int findLatestStep(int[] arr, int m) {
int n = arr.length;
if (m == n) {
return n;
}
boolean[] vis = new boolean[n];
p = new int[n];
size = new int[n];
for (int i = 0; i < n; ++i) {
p[i] = i;
size[i] = 1;
}
int ans = -1;
for (int i = 0; i < n; ++i) {
int v = arr[i] - 1;
if (v > 0 && vis[v - 1]) {
if (size[find(v - 1)] == m) {
ans = i;
}
union(v, v - 1);
}
if (v < n - 1 && vis[v + 1]) {
if (size[find(v + 1)] == m) {
ans = i;
}
union(v, v + 1);
}
vis[v] = true;
}
return ans;
}
private int find(int x) {
if (p[x] != x) {
p[x] = find(p[x]);
}
return p[x];
}
private void union(int a, int b) {
int pa = find(a), pb = find(b);
if (pa == pb) {
return;
}
p[pa] = pb;
size[pb] += size[pa];
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 | class Solution {
public:
vector<int> p;
vector<int> size;
int findLatestStep(vector<int>& arr, int m) {
int n = arr.size();
if (m == n) return n;
p.resize(n);
size.assign(n, 1);
for (int i = 0; i < n; ++i) p[i] = i;
int ans = -1;
vector<int> vis(n);
for (int i = 0; i < n; ++i) {
int v = arr[i] - 1;
if (v && vis[v - 1]) {
if (size[find(v - 1)] == m) ans = i;
unite(v, v - 1);
}
if (v < n - 1 && vis[v + 1]) {
if (size[find(v + 1)] == m) ans = i;
unite(v, v + 1);
}
vis[v] = true;
}
return ans;
}
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
void unite(int a, int b) {
int pa = find(a), pb = find(b);
if (pa == pb) return;
p[pa] = pb;
size[pb] += size[pa];
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 | func findLatestStep(arr []int, m int) int {
n := len(arr)
if m == n {
return n
}
p := make([]int, n)
size := make([]int, n)
vis := make([]bool, n)
for i := range p {
p[i] = i
size[i] = 1
}
var find func(int) int
find = func(x int) int {
if p[x] != x {
p[x] = find(p[x])
}
return p[x]
}
union := func(a, b int) {
pa, pb := find(a), find(b)
if pa == pb {
return
}
p[pa] = pb
size[pb] += size[pa]
}
ans := -1
for i, v := range arr {
v--
if v > 0 && vis[v-1] {
if size[find(v-1)] == m {
ans = i
}
union(v, v-1)
}
if v < n-1 && vis[v+1] {
if size[find(v+1)] == m {
ans = i
}
union(v, v+1)
}
vis[v] = true
}
return ans
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 | const findLatestStep = function (arr, m) {
function find(x) {
if (p[x] !== x) {
p[x] = find(p[x]);
}
return p[x];
}
function union(a, b) {
const pa = find(a);
const pb = find(b);
if (pa === pb) {
return;
}
p[pa] = pb;
size[pb] += size[pa];
}
const n = arr.length;
if (m === n) {
return n;
}
const vis = Array(n).fill(false);
const p = Array.from({ length: n }, (_, i) => i);
const size = Array(n).fill(1);
let ans = -1;
for (let i = 0; i < n; ++i) {
const v = arr[i] - 1;
if (v > 0 && vis[v - 1]) {
if (size[find(v - 1)] === m) {
ans = i;
}
union(v, v - 1);
}
if (v < n - 1 && vis[v + 1]) {
if (size[find(v + 1)] === m) {
ans = i;
}
union(v, v + 1);
}
vis[v] = true;
}
return ans;
};
|
方法二:动态维护区间端点的长度
我们其实并不需要去通过查找并查集来获取每个区间长度,我们只需要在每个区间端点处记录每个区间长度,由于合并的时候只会访问区间端点,所以合并区间的时候修改端点区间长度即可。
时间复杂度 $O(n)$。
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | class Solution:
def findLatestStep(self, arr: List[int], m: int) -> int:
n = len(arr)
if m == n:
return n
cnt = [0] * (n + 2)
ans = -1
for i, v in enumerate(arr):
v -= 1
l, r = cnt[v - 1], cnt[v + 1]
if l == m or r == m:
ans = i
cnt[v - l] = cnt[v + r] = l + r + 1
return ans
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | class Solution {
public int findLatestStep(int[] arr, int m) {
int n = arr.length;
if (m == n) {
return n;
}
int[] cnt = new int[n + 2];
int ans = -1;
for (int i = 0; i < n; ++i) {
int v = arr[i];
int l = cnt[v - 1], r = cnt[v + 1];
if (l == m || r == m) {
ans = i;
}
cnt[v - l] = l + r + 1;
cnt[v + r] = l + r + 1;
}
return ans;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | class Solution {
public:
int findLatestStep(vector<int>& arr, int m) {
int n = arr.size();
if (m == n) return n;
vector<int> cnt(n + 2);
int ans = -1;
for (int i = 0; i < n; ++i) {
int v = arr[i];
int l = cnt[v - 1], r = cnt[v + 1];
if (l == m || r == m) ans = i;
cnt[v - l] = cnt[v + r] = l + r + 1;
}
return ans;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | func findLatestStep(arr []int, m int) int {
n := len(arr)
if m == n {
return n
}
cnt := make([]int, n+2)
ans := -1
for i, v := range arr {
l, r := cnt[v-1], cnt[v+1]
if l == m || r == m {
ans = i
}
cnt[v-l], cnt[v+r] = l+r+1, l+r+1
}
return ans
}
|