最小区间
难度:
标签:
题目描述
代码结果
运行时间: 107 ms, 内存: 23.4 MB
/*
思路:
虽然Java Stream不适合处理此问题的所有步骤,但可以用于初始化列表和获取最小值最大值等辅助操作。
我们将使用最小堆来解决主要问题。
*/
import java.util.*;
import java.util.stream.*;
public class SmallestRangeStream {
public int[] smallestRange(List<List<Integer>> nums) {
PriorityQueue<int[]> minHeap = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
int currentMax = nums.stream().mapToInt(list -> list.get(0)).max().orElse(Integer.MIN_VALUE);
nums.stream().map(list -> new int[]{list.get(0), nums.indexOf(list), 0})
.forEach(minHeap::offer);
int minRange = Integer.MAX_VALUE;
int start = -1;
int end = -1;
while (minHeap.size() == nums.size()) {
int[] current = minHeap.poll();
int currentMin = current[0];
int listIndex = current[1];
int elementIndex = current[2];
if (currentMax - currentMin < minRange) {
minRange = currentMax - currentMin;
start = currentMin;
end = currentMax;
}
if (elementIndex + 1 < nums.get(listIndex).size()) {
int nextElement = nums.get(listIndex).get(elementIndex + 1);
minHeap.offer(new int[]{nextElement, listIndex, elementIndex + 1});
currentMax = Math.max(currentMax, nextElement);
}
}
return new int[]{start, end};
}
}
解释
方法:
该题解的思路是先将每个数字与其所在的组号绑定在一起,形成(数字,组号)的元组,然后对这些元组进行排序。接着使用滑动窗口的方法,通过左右指针维护一个窗口,保证窗口内包含了所有的组。在滑动窗口的过程中,记录下窗口大小最小的区间作为答案。具体实现时,使用哈希表 mp 来统计当前窗口内每个组出现的次数,当 mp 的大小等于总组数时,说明当前窗口已经包含了所有的组,此时更新最小区间,并尝试通过收缩左边界来缩小区间大小。
时间复杂度:
O(n log n)
空间复杂度:
O(n)
代码细节讲解
🦆
在算法中,如何确保在初始化哈希表`mp`时,它已经包含了所有必要的组号,以便正确地追踪每个组的元素?
▷🦆
对于边界情况,比如当一个或多个列表为空时,这个算法是否仍然有效?如果无效,如何修改算法以处理这种情况?
▷🦆
在滑动窗口法中,为何选择对元组`(数字, 组号)`进行排序,而不是直接在原始列表上滑动?排序带来了哪些计算上的优势或必要性?
▷🦆
在滑动窗口中,当删除哈希表`mp`中的一个元素(即当某个组在窗口中的计数为0时)后,为什么立即移动左指针`l`?这样的操作是否可能错过某些潜在的最小区间?
▷