“小R的数组最小化问题”题目要求
一、问题描述
小U在经营一家餐厅,他希望根据每天的客流量数据来优化备货策略。为此,他需要计算从第一天到第i天的中位客流量,并将其四舍五入为整数。
给定餐厅营业的总天数N,以及每天的客流量数据Ri,你需要输出一个长度为N的序列,其中第i个值表示从第一天到第ii天的中位客流量。所有输出结果都要求进行四舍五入。
二、测试样例
样例1:
输入:
N = 5 ,R = [1, 2, 3, 4, 10]
输出:[1, 2, 2, 3, 3]
样例2:
输入:
N = 3 ,R = [5, 10, 15]
输出:[5, 8, 10]
样例3:
输入:
N = 4 ,R = [2, 8, 6, 7]
输出:[2, 5, 6, 7]
三、题目解析
3.1代码思路
-
中位数的计算:
- 如果天数是奇数,中位数是排序后的中间值。
- 如果天数是偶数,中位数是排序后中间两个数的平均值。
-
数据结构:
- 我们可以使用一个数组来存储每天的客流量。
- 为了快速找到中位数,可以使用一个排序的数据结构,比如
PriorityQueue(优先队列)或者TreeSet。
-
算法步骤:
- 初始化一个结果数组
result,用于存储每天的中位数。 - 遍历每一天的客流量,将客流量加入到一个排序的数据结构中。
- 根据当前的天数(奇数或偶数),计算中位数并四舍五入。
- 将计算出的中位数存入结果数组
result。
- 初始化一个结果数组
3.2详细代码
import java.util.Arrays;
import java.util.PriorityQueue;
public class Main {
public static int[] solution(int N, int[] R) {
int[] result = new int[N];
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);
for (int i = 0; i < N; i++) {
// 将当前客流量加入到合适的数据结构中
addNumber(R[i], minHeap, maxHeap);
// 平衡两个堆的大小
balanceHeaps(minHeap, maxHeap);
// 计算中位数并四舍五入
result[i] = getMedian(minHeap, maxHeap);
}
return result;
}
private static void addNumber(int num, PriorityQueue<Integer> minHeap, PriorityQueue<Integer> maxHeap) {
// 将新数字加入到合适的数据结构中
if (maxHeap.isEmpty() || num <= maxHeap.peek()) {
maxHeap.add(num);
} else {
minHeap.add(num);
}
}
private static void balanceHeaps(PriorityQueue<Integer> minHeap, PriorityQueue<Integer> maxHeap) {
// 平衡两个堆的大小,使得两个堆的大小差不超过1
if (maxHeap.size() > minHeap.size() + 1) {
minHeap.add(maxHeap.poll());
} else if (minHeap.size() > maxHeap.size()) {
maxHeap.add(minHeap.poll());
}
}
private static int getMedian(PriorityQueue<Integer> minHeap, PriorityQueue<Integer> maxHeap) {
// 根据两个堆的大小计算中位数并四舍五入
if (maxHeap.size() == minHeap.size()) {
return (int) Math.round((maxHeap.peek() + minHeap.peek()) / 2.0);
} else {
return maxHeap.peek();
}
}
public static void main(String[] args) {
System.out.println(Arrays.equals(solution(5, new int[]{1, 2, 3, 4, 10}), new int[]{1, 2, 2, 3, 3}));
System.out.println(Arrays.equals(solution(3, new int[]{5, 10, 15}), new int[]{5, 8, 10}));
System.out.println(Arrays.equals(solution(4, new int[]{2, 8, 6, 7}), new int[]{2, 5, 6, 7}));
}
}
四、知识总结
1.中位数的定义
- 奇数个元素:中位数是排序后中间的那个数。
- 偶数个元素:中位数是排序后中间两个数的平均值。
2. 数据流中位数的挑战
在动态数据流中,每次加入新数据后都需要实时更新中位数。如果每次都重新排序,效率会很低,因此我们需要优化的算法。
3. 解决思路:双堆法
- 最大堆(
maxHeap) :存储较小的一半数据,堆顶是这部分数据的最大值。 - 最小堆(
minHeap) :存储较大的一半数据,堆顶是这部分数据的最小值。
核心操作:
- 动态平衡两个堆的大小,使它们的元素个数差不超过 1。
- 根据堆顶元素快速计算中位数。
4.性能分析
时间复杂度:
- 插入和调整堆的复杂度为 O(logN),总体复杂度为 O(NlogN)。
空间复杂度:
- 使用两个堆存储数据,空间复杂度为 O(N)。