leetcode中两道关于中位数的题295和480

本文探讨了LeetCode上的第295和480题,这两道题目都涉及到寻找中位数。解题策略是利用两个堆,一个为最小堆,另一个为最大堆,以此来动态维护数列的中位数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

两道题的思路是一样的,都是建立2个堆,一个是最小堆,一个是最大堆

295题

/*
 * Design a data structure that supports the following two operations:

void addNum(int num) - Add a integer number from the data stream to the data structure.
double findMedian() - Return the median of all elements so far.
 * */
import java.util.Comparator;
import java.util.PriorityQueue;


//方法类似与480题的sliding window median
 /*
     Use two Heaps to store numbers. maxHeap for numbers smaller than current
	 * median, minHeap for numbers bigger than and equal to current median. A
	 * small trick I used is always make size of minHeap equal (when there are
	 * even numbers) or 1 element more (when there are odd numbers) than the
	 * size of maxHeap
	*/
public class MedianFinder {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		MedianFinder mf = new MedianFinder();
		mf.addNum(1);
		mf.addNum(2);
		System.out.println(mf.findMedian());
		mf.addNum(3);
		System.out.println(mf.findMedian());
	}

	PriorityQueue<Integer> minHeap;//使minHeap中的个数等于或者比maxHeap多1,这样对于返回中位数操作就相对简单
	PriorityQueue<Integer> maxHeap;

	public MedianFinder() {
		this.minHeap = new PriorityQueue<>();
		this.maxHeap = new PriorityQueue<>(new Comparator<Integer>() {
			public int compare(Integer o1, Integer o2) {
				return o2.compareTo(o1);
			}
		});
	}

	public void addNum(int num) {
		if (num < findMedian())
			maxHeap.add(num);
		else
			minHeap.add(num);
		if (maxHeap.size() > minHeap.size())
			minHeap.add(maxHeap.poll());
		if (minHeap.size() - maxHeap.size() > 1)
			maxHeap.add(minHeap.poll());
	}

	public double findMedian() {
		if (minHeap.isEmpty() && maxHeap.isEmpty())
			return 0;
		if (minHeap.size() == maxHeap.size())
			return ((double) minHeap.peek() + (double) maxHeap.peek()) / 2.0;
		else
			return (double) minHeap.peek();
	}
}


480提,其实就是在295的基础上增加了一个窗口k以及一个remove函数

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;

/*
 * Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.

Examples: 
[2,3,4] , the median is 3

[2,3], the median is (2 + 3) / 2 = 2.5

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Your job is to output the median array for each window in the original array.

For example,
Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.

Window position                Median
---------------               -----
[1  3  -1] -3  5  3  6  7       1
 1 [3  -1  -3] 5  3  6  7       -1
 1  3 [-1  -3  5] 3  6  7       -1
 1  3  -1 [-3  5  3] 6  7       3
 1  3  -1  -3 [5  3  6] 7       5
 1  3  -1  -3  5 [3  6  7]      6
Therefore, return the median sliding window as [1,-1,-1,3,5,6].
 * */
public class Solution {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
//		int[] nums = { 1, 4, 2, 3 };
//		double[] res = Solution.medianSlidingWindow(nums, 4);
//		for (double dd : res)
//			System.out.println(dd);
	}

	// TLE超时
	public static double[] medianSlidingWindow2(int[] nums, int k) {
		int len = nums.length;
		if (len == 0 || k == 0)
			return new double[0];
		List<Double> list = new ArrayList<>();
		double[] window = new double[k];
		double[] windowCopy = new double[k];
		for (int i = 0; i < len && i + k <= len; ++i) {
			for (int j = i; j < i + k; ++j) {
				window[j - i] = nums[j];
				windowCopy[j - i] = window[j - i];
			}
			Arrays.sort(windowCopy);
			if (k % 2 != 0)
				list.add(windowCopy[k / 2]);
			else
				list.add((windowCopy[k / 2 - 1] + windowCopy[k / 2]) / 2);
		}
		double[] res = new double[list.size()];
		for (int i = 0; i < list.size(); ++i)
			res[i] = list.get(i);
		return res;
	}

	/*
	 * Use two Heaps to store numbers. maxHeap for numbers smaller than current
	 * median, minHeap for numbers bigger than and equal to current median. A
	 * small trick I used is always make size of minHeap equal (when there are
	 * even numbers) or 1 element more (when there are odd numbers) than the
	 * size of maxHeap. Then it will become very easy to calculate current
	 * median. Keep adding number from the right side of the sliding window and
	 * remove number from left side of the sliding window. And keep adding
	 * current median to the result.
	 */
	
	//2个堆加起来节点个数为k个
	PriorityQueue<Integer> minHeap = new PriorityQueue<>();
	PriorityQueue<Integer> maxHeap = new PriorityQueue<>(new Comparator<Integer>() {
		public int compare(Integer o1, Integer o2) {
			return o2.compareTo(o1);
		}
	});

	public double[] medianSlidingWindow(int[] nums, int k) {
		int n = nums.length - k + 1;
		double[] res = new double[n];
		if (n <= 0)
			return new double[0];
		for (int i = 0; i <= nums.length; ++i) {
			if (i >= k) {
				res[i - k] = getMedian();
				remove(nums[i - k]);
			}
			if (i < nums.length)
				add(nums[i]);
		}
		return res;
	}

	public void add(int num) {
		if (num < getMedian()) {
			maxHeap.add(num);
		} else
			minHeap.add(num);
		if (maxHeap.size() > minHeap.size())
			minHeap.add(maxHeap.poll());
		if (minHeap.size() - maxHeap.size() > 1)
			maxHeap.add(minHeap.poll());
	}

	public void remove(int num) {
		if (num < getMedian()) {
			maxHeap.remove(num);
		} else
			minHeap.remove(num);
		if (maxHeap.size() > minHeap.size())
			minHeap.add(maxHeap.poll());
		if (minHeap.size() - maxHeap.size() > 1)
			maxHeap.add(minHeap.poll());
	}

	public double getMedian() {
		if (minHeap.isEmpty() && maxHeap.isEmpty())
			return 0;
		if (maxHeap.size() == minHeap.size())
			return ((double) maxHeap.peek() + (double) minHeap.peek()) / 2.0;
		else
			return (double) minHeap.peek();
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值