数据流中的中位数

一、题目描述

中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。

例如,

[2,3,4] 的中位数是 3

[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构:

void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3) 
findMedian() -> 2

二、答题链接

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-median-from-data-stream

三、JAVA代码

class MedianFinder {

   private PriorityQueue<Integer> min = new PriorityQueue<>();  //默认为最小堆
   private PriorityQueue<Integer> max = new PriorityQueue<>(new Comparator<Integer>() {
        @Override
        public int compare(Integer i, Integer j) {
            return j -i;
        }
    });

public MedianFinder() {
    
}

public void addNum(int num) {
    int size = min.size() + max.size();
        if((size&1)==0){     //注意位运算需要用括号括起来
            //偶数:max中增加元素
            min.offer(num);
            num=min.poll();
            max.offer(num);
        }else{
            //奇数:min中增加元素
            max.offer(num);
            num=max.poll();
            min.offer(num);
        }
}

public double findMedian() {
    int size = min.size() + max.size();
    if ((size & 1) == 0)  //为偶数时返回中间两值的平均数,即min堆堆顶元素和max堆顶元素的均值
        return (min.peek() + max.peek()) / 2.0;
    return max.peek(); //为奇数时返回中间值,即max堆的堆顶元素
}
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */

四、写给自己

(1)比较函数
  • 注意复习匿名内部类
  • Comparator接口中需要重写的方法是public int compare(T o1, T o2)
  • Comparable接口中需要重写的方法是public int compareTo(T another)
 private PriorityQueue<Integer> max = new PriorityQueue<>(new Comparator<Integer>() {
        @Override
        public int compare(Integer i, Integer j) {
            return j -i;
        }
    });

关于Comparator和Compareble的比较:

1)Comparable 与Comparator都是java的接口,用来对自定义的实体对象进行比较;

2)Comparable 是定义在实体类内部的,所以实体类对象本身就有比较大小的可能。但如果想换一种比较规则,如先按年龄后按名字排序,那么就必须修改实体类Person本身;

3)Comparator是在实体类外部实现比较器的,所以对List排序时必须同时传入数据和比较器,如Collections.sort(list, new MyComparator());如果想换一种比较规则,则仅需要修改比较器MyComparator,而实体类Person则不需要改变;所以建议使用这种方法;

4)Comparable实现代码相对简单,Comparator实现代码相对复杂一点,但还是建议使用Comparator方法。

原文链接:https://blog.csdn.net/wxx614817/article/details/50628197

(2)Integer与Double的转换
return (min.peek()+max.peek()) / Double.valueOf(2);  //可Accept
return (min.peek()+max.peek() ) / 2.0; //可Accept
return (min.peek()+max.peek() ) / 2; //错误
return Double.valueOf( (max.peek() + min.peek())/2 ); //错误

关于Double.valueOf()

//参数为double类型
public static Double valueOf(double d) {
        return new Double(d);
}
//参数为String类型
public static Double valueOf(String s) throws NumberFormatException {
        return new Double(parseDouble(s));
}

关于Integer类型数的除法:

    public void test(){
        System.out.println(5/3); //输出 1,存在精度就是问题
        System.out.println((double)(5/3)); //输出 1.0,存在精度丢失问题
        System.out.println(Double.valueOf(5/3)); //输出 1.0,存在精度丢失问题
        System.out.println(5.0/3);  // 输出1.6666666666666667
    }

从上述测试来看,两个Integer类型数进行除法运算,只会保留整数,即使将结果转换为double,也只是在小数位上添加0,实际计算所得的小数部分已经丢失。

如果保留小数部分,在进行除法之前就要完成将Integer类型进行转化,例如*1.0或者new Double(2)、亦或者Double.valueOf(2);

(3)float与double

float:单精度类型,精度是8位有效数字,取值范围是10的-38次方到10的38次方,float占用4个字节的存储空间
double:双精度类型,精度是17位有效数字,取值范围是10的-308次方到10的308次方,double占用8个字节的存储空间

若不声明的,默认小数都用double来表示,所以如果要用float的话,则应该在其后加上f
例如:float a=1.63;//会显示错误,正确的写法为float a=1.63f;
则会提示不能将double转化成float 这成为窄型转化

注意float是8位有效数字,第7位数字将会产生四舍五入
所以如果一个float变量 这样定义: float a=1.32344435; 则第7位将产生四舍五入(5及5以下的都将舍去)

一般开发中建议用double 修饰小数

原文链接:https://blog.csdn.net/qzw5235641/article/details/84676881

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值