一、堆排序
题:如何得到一个数据流中的中位数?(动态、实时,在任意时刻都能够直接拿到我们想要的均值而不去计算下标取值)
堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:
小顶堆:Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]
大顶堆:Key[i]>=Key[2i+1]&&key>=key[2i+2]
题:如何得到一个数据流中的中位数?(动态、实时,在任意时刻都能够直接拿到我们想要的均值而不去计算下标取值)
思路:
需要求的是中位数,如果我将 1 2 3 4 5 6 7 8定为最终的数据流
- 此时的中位数是4+5求均值。为什么是4,为什么是5
- 利用队列我们就可以看得很清楚,4是前半部分最大的值,肯定是维系在大顶堆
- 而5是后半部分的最小值,肯定是维系在小顶堆。
- 问题就好理解了:使用小顶堆存大数据,使用大顶堆存小数据。这样堆顶一取出就是中位数了。
代码中奇数时刻大顶堆存值,所以遇到奇数时刻,大顶堆直接弹出就是中位数
public class stockMedium {
private int cnt = 0;
private PriorityQueue<Integer> low = new PriorityQueue<>();
// 默认维护小顶堆
private PriorityQueue<Integer> high = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
public void Insert(Integer num) {
// 数量++
cnt++;
// 如果为奇数的话
if ((cnt & 1) == 1) {
// 由于奇数,需要存放在大顶堆上
// 但是呢,现在你不知道num与小顶堆的情况
// 小顶堆存放的是后半段大的数
// 如果当前值比小顶堆上的那个数更大
if (!low.isEmpty() && num > low.peek()) {
// 存进去
low.offer(num);
// 然后在将那个最小的吐出来
num = low.poll();
} // 最小的就放到大顶堆,因为它存放前半段
high.offer(num);
} else {
// 偶数的话,此时需要存放的是小的数
// 注意无论是大顶堆还是小顶堆,吐出数的前提是得有数
if (!high.isEmpty() && num < high.peek()) {
high.offer(num);
num = high.poll();
} // 大数被吐出,小顶堆插入
low.offer(num);
}
}
public Double GetMedian() {// 表明是偶数
double res = 0;
// 奇数
if ((cnt & 1) == 1) {
res = high.peek();
} else {
res = (high.peek() + low.peek()) / 2.0;
}
return res;
}
}
二、归并排序
思路:该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。
输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。
即输出P%1000000007
归并排序的改进,把数据分成前后两个数组(递归分到每个数组仅有一个数据项),
合并数组,合并时,出现前面的数组值array[i]大于后面数组值array[j]时,则前面
数组array[i]~array[mid]都是大于array[j]的,count += mid+1 - i
public class InversePairs {
public int InversePairs(int [] array) {
if(array==null||array.length==0)
return 0;
int[] copy = new int[array.length];
int count = sort(array,copy,0,array.length-1);
return count;
}
private int sort(int[] array, int[] copy, int low, int high) {
if(low==high)
return 0;
int mid = (low+high)>>1;
int leftCount = sort(array,copy,low,mid)%1000000007;
int rightCount = sort(array,copy,mid+1,high)%1000000007;
int count = 0;
int loc = high;
int i = mid;
int j = high;
while (i>=low&&j>=mid+1){
if(array[i]>array[j]){
count += j-mid;
if(count>=1000000007)//数值过大求余
{
count%=1000000007;
}
copy[loc] = array[i];
i--;
loc--;
}
else{
copy[loc] = array[j];
j--;
loc--;
}
}
for(;i>=low;i--)
{
copy[loc--]=array[i];
}
for(;j>mid;j--)
{
copy[loc--]=array[j];
}
for(int s=low;s<=high;s++)
{
array[s] = copy[s];
}
return (leftCount+rightCount+count)%1000000007;
}
}