AI刷题之小R的数组最小化问题 | 豆包MarsCode AI刷题

57 阅读3分钟

“小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代码思路

  1. 中位数的计算

    • 如果天数是奇数,中位数是排序后的中间值。
    • 如果天数是偶数,中位数是排序后中间两个数的平均值。
  2. 数据结构

    • 我们可以使用一个数组来存储每天的客流量。
    • 为了快速找到中位数,可以使用一个排序的数据结构,比如PriorityQueue(优先队列)或者TreeSet
  3. 算法步骤

    • 初始化一个结果数组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(log⁡N),总体复杂度为 O(Nlog⁡N)。

空间复杂度

-   使用两个堆存储数据,空间复杂度为 O(N)。