算法通关村第十四关黄金挑战——堆解决数据流的中位数和数组求中位数的方法总结

关注微信公众号:怒码少年。回复关键词【电子书】,领取多本计算机相关电子书

遇到任何问题都可以在后台向我提问,完全免费!!大家共同进步!!

大家好,我是怒码少年小码。

本篇主要是讲讲如何利用堆来求一个数组的中位数,以及求数组中位数的常见方法主题。

数据流的中位数

LeetCode 295:中位数 是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。

  • 例如 arr = [2,3,4] 的中位数是 3 。
  • 例如 arr = [1,2,3,4] 的中位数是 (2 + 3) / 2 = 2.5 。

分析:观察数组,偶数情况下,把数组分成两份,中位数就是前半数组的最大值和后半数组的最小值的平均值

因此,我们可以创建一个最小堆和最大堆,分别保存数组的较小的那一部分和数组中较大的一部分。要求最小堆的元素数量>= 最大堆的元素数量,两个堆中的元素数量相差不大于一个元素:

  • 两个堆中的元素数量相等。表示数组元素总数是偶数------中位数是最小堆和最大堆的堆顶元素的平均值。
  • 两个堆中的元素数量不相等(最小堆的元素数量>最大堆的元素数量)。表示数组元素总数是奇数------中位数是最小堆的堆顶元素。

堆的构建在C++和python中太麻烦,这里我们利用Java中的优先队列``来解决

java 复制代码
PriorityQueue<Integer> minHeap;
PriorityQueue<Integer> maxHeap;

public MedianFinder() {
    this.minHeap = new PriorityQueue<>();
    this.maxHeap = new PriorityQueue<>((a,b)->b-a);
}
    
public void addNum(int num) {
    //num比minHeap的最小值大,说明它可以插入到最小堆中
    if(minHeap.isEmpty() || num > minHeap.peek()){
        minHeap.offer(num);
        //minHeap中的元素个数比maxHeap多2个元素,就平衡一下
        if(minHeap.size()-maxHeap.size() > 1){
            maxHeap.offer(minHeap.poll());
        }
    }else{
        maxHeap.offer(num);
        //确保多的那一个元素一定在最小堆,也就是总数是奇数的时候,中间值在最小堆中
        if(maxHeap.size() > minHeap.size() ){
            minHeap.offer(maxHeap.poll());
        }
    }
}
    
public double findMedian() {
    if(minHeap.size() > maxHeap.size()){
        return minHeap.peek();
    }else{
        return (minHeap.peek() + maxHeap.peek()) / 2.0;
    }
}

求数组中位数的方法总结

排序法:

利用某种排序算法将数组进行排序,然后根据数组长度的奇偶性确定中位数的位置。如果数组长度为奇数,中位数即为排序后的中间元素;如果数组长度为偶数,中位数为排序后中间两个元素的平均值。

java 复制代码
import java.util.Arrays;

public class Median {
    public static double findMedian(int[] nums) {
        Arrays.sort(nums);
        int n = nums.length;
        if (n % 2 == 0) {
            return (nums[n / 2 - 1] + nums[n / 2]) / 2.0;
        } else {
            return nums[n / 2];
        }
    }
}

堆法:

(就是上面写的方法)利用最大堆和最小堆,将数组分成两部分。最大堆存储较小的一部分元素,最小堆存储较大的一部分元素。如果两个堆的大小相等,则中位数为两个堆顶元素的平均值;否则,中位数为较大堆的堆顶元素。

双指针法:

对数组进行两端指针的遍历。在遍历过程中,根据条件将指针向中间移动,直到找到中位数。这种方法适用于已经有序或部分有序的数组。

java 复制代码
import java.util.Arrays;

public class Median {
    public static double findMedian(int[] nums) {
        Arrays.sort(nums);
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            left++;
            right--;
        }
        if (left == right) {
            return nums[left];
        } else {
            return (nums[left] + nums[right]) / 2.0;
        }
    }
}

快速选择算法:

基于快速排序的思想,通过每次选择一个元素作为基准点将数组分成两部分,然后根据基准点的位置继续递归搜索中位数所在的部分,直到找到中位数。

java 复制代码
import java.util.Random;

public class Median {
    public static double findMedian(int[] nums) {
        int n = nums.length;
        if (n % 2 == 0) {
            return (quickSelect(nums, 0, n - 1, n / 2 - 1) + quickSelect(nums, 0, n - 1, n / 2)) / 2.0;
        } else {
            return quickSelect(nums, 0, n - 1, n / 2);
        }
    }

    private static int quickSelect(int[] nums, int left, int right, int k) {
        int pivotIndex = partition(nums, left, right);
        if (pivotIndex == k) {
            return nums[k];
        } else if (pivotIndex < k) {
            return quickSelect(nums, pivotIndex + 1, right, k);
        } else {
            return quickSelect(nums, left, pivotIndex - 1, k);
        }
    }

    private static int partition(int[] nums, int left, int right) {
        int randomIndex = new Random().nextInt(right - left + 1) + left;
        swap(nums, randomIndex, right);
        int pivot = nums[right];
        int i = left - 1;
        for (int j = left; j < right; j++) {
            if (nums[j] <= pivot) {
                i++;
                swap(nums, i, j);
            }
        }
        swap(nums, i + 1, right);
        return i + 1;
    }

    private static void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

END

关关难过,关关过!算法就是要长期练习!大家加油!!

关注微信公众号:怒码少年。

遇到任何问题都可以在后台向我提问,完全免费!!大家共同进步!!

相关推荐
uhakadotcom1 小时前
Apache Airflow入门指南:数据管道的强大工具
算法·面试·github
跳跳糖炒酸奶1 小时前
第四章、Isaacsim在GUI中构建机器人(2):组装一个简单的机器人
人工智能·python·算法·ubuntu·机器人
绵绵细雨中的乡音2 小时前
动态规划-第六篇
算法·动态规划
程序员黄同学2 小时前
动态规划,如何应用动态规划解决实际问题?
算法·动态规划
march_birds2 小时前
FreeRTOS 与 RT-Thread 事件组对比分析
c语言·单片机·算法·系统架构
斯汤雷3 小时前
Matlab绘图案例,设置图片大小,坐标轴比例为黄金比
数据库·人工智能·算法·matlab·信息可视化
云 无 心 以 出 岫3 小时前
贪心算法QwQ
数据结构·c++·算法·贪心算法
俏布斯3 小时前
算法日常记录
java·算法·leetcode
独好紫罗兰3 小时前
洛谷题单3-P5719 【深基4.例3】分类平均-python-流程图重构
开发语言·python·算法
SheepMeMe4 小时前
蓝桥杯2024省赛PythonB组——日期问题
python·算法·蓝桥杯