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

两道题的思路是一样的,都是建立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 minHeap;//使minHeap中的个数等于或者比maxHeap多1,这样对于返回中位数操作就相对简单
	PriorityQueue maxHeap;

	public MedianFinder() {
		this.minHeap = new PriorityQueue<>();
		this.maxHeap = new PriorityQueue<>(new Comparator() {
			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 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 minHeap = new PriorityQueue<>();
	PriorityQueue maxHeap = new PriorityQueue<>(new Comparator() {
		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();
	}
}



你可能感兴趣的:(面试,leetcode,算法)