LeetCode1562. 查找大小为 M 的最新分组
给你一个数组 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.length1 <= arr[i] <= narr中的所有整数 互不相同1 <= m <= arr.length
思路分析
使用并查集,每遍历一个元素,将元素并入集合,合并符合条件的集合。并判断集合长度是否满足M,满足vaild+1,不满足分两种情况,第一种原先满足条件的集合被合并,此时需要vaild-1;第二种原先满足条件的集合未被合并,不需要进行任何操作。每次循环最后判断vaild是否大于0,大于更新last,小于或者等于不进行任何操作。
维护三个数组, nums[i]:表示以i为根节点的集合中元素的个数,初始值都为1,每一次集合合并都需要更新该数组 vis[i]:i元素是否被遍历过 set[i]:集合
算法代码
public int findLatestStep(int[] arr, int m) {
if (arr == null || arr.length == 0) throw new IllegalArgumentException("invalid param");
int n = arr.length;
if (m > n) return -1;
if (m == n) return n;
// 转化为时间数组
int[] times = new int[n];
int time = 1;
for (int num: arr) times[num - 1] = time++;
// 问题转化为窗口m中最大值与左右边界的比较问题
int[] left = new int[n], right = new int[n];
for (int i = 0; i < n; i++) {
if (i % m == 0) left[i] = times[i];
else left[i] = Math.max(left[i - 1], times[i]);
int j = n - i - 1;
if (j == n - 1 || (j + 1) % m == 0) right[j] = times[j];
else right[j] = Math.max(right[j + 1], times[j]);
}
int res = 0;
// 遍历窗口
for (int i = 0; i <= n - m; i++) {
// 窗口最大值
int max = Math.max(left[i + m - 1], right[i]);
// 比较左右邻居
if (i == 0 && times[m] > max) res = times[m];
else if (i == n - m && times[n - m - 1] > max) res = Math.max(res, times[n - m - 1]);
else if (i > 0 && i < n - m && times[i - 1] > max && times[i + m] > max) res = Math.max(res, Math.min(times[i - 1], times[i + m]));
}
return res - 1;
}
结果详情
算法复杂度
- 空间复杂度:
- 时间复杂度:
在掘金(JUEJIN)一起进步,一起成长!