【HackerRank】Median
题目链接:Median
做了整整一天T_T
尝试了各种方法:
首先看了解答,可以用multiset,但是发现java不支持;
然后想起来用堆,这个基本思想其实很巧妙的,就是维护一个最大堆和最小堆,最大堆存放前半部分较小的元素,最小堆存放后半部分较大的元素,并且最大堆的所有元素小于最小堆的所有元素;保持最大堆最多比最小堆多一个元素。每次插入元素的时候都先插入到最大堆,如果发现最大堆比最小堆多了两个个,那么就从最大堆里面拿出最大的放到最小堆里面;如果发现最大堆里面新插入的元素破坏了最大堆所有元素小于最小堆所有元素的原则,就把最大堆的最大元素和最小堆的最小元素交换。
这种做法可以用java的priority queue实现,插入操作的时间复杂度也只有O(log(n));但是堆结构非常不利于查找操作,所有删除的时候就很麻烦了,时间复杂度会达到O(n),会超时。
接下来google了一下,发现简单的插入排序和二分结合在一起就可以了,非常开森的自己码了一个二分,码完了又超时,心都碎了,明明人家拿C++码的二分就不超时。
后来发现java的ArrayList自带的就有Collections.binarySearch(),于是又拿这个尝试,果然变快了(为什么要歧视我自己写的二分,why......),但是最后一个例子又超时。想起来以前的教训,用BufferedReader代替了Scanner,然后就过了......java真的好坑啊,一不小心就超时。
最后代码如下:
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStreamReader; 4 import java.nio.Buffer; 5 import java.util.*; 6 class Solution{ 7 private static int numberOfItems = 0; 8 private static void add(int number,ArrayList<Integer> a){ 9 int positon = Collections.binarySearch(a, number); 10 if(positon<0) 11 positon = -positon-1; 12 13 a.add(positon,number); 14 numberOfItems++; 15 printMedia(a); 16 } 17 18 public static void printMedia(ArrayList<Integer> a){ 19 if(numberOfItems>0){ 20 if(numberOfItems%2==0) 21 { 22 long num = (long)a.get(numberOfItems/2)+(long)a.get(numberOfItems/2-1); 23 if(num%2 == 0) 24 System.out.printf("%d\n",num/2); 25 else { 26 System.out.printf("%.1f\n", num/2.0); 27 } 28 } 29 else { 30 System.out.println(a.get(numberOfItems/2)); 31 } 32 } 33 else { 34 System.out.println("Wrong!"); 35 } 36 } 37 public static void remove(int value,ArrayList<Integer> a){ 38 int position = Collections.binarySearch(a, value); 39 if(position < 0) 40 System.out.println("Wrong!"); 41 else{ 42 a.remove(position); 43 numberOfItems--; 44 printMedia(a); 45 } 46 } 47 public static void main( String args[] )throws IOException{ 48 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 49 int N = Integer.parseInt(br.readLine()); 50 51 ArrayList<Integer> a = new ArrayList<Integer>(); 52 for(int i = 0;i < N;i++){ 53 String[] words = br.readLine().trim().split(" "); 54 if(words[0].equals("a")){ 55 add(Integer.parseInt(words[1]), a); 56 } 57 else{ 58 remove(Integer.parseInt(words[1]), a); 59 } 60 } 61 } 62 }
不过这么折腾确实学到不少东西,总结一下:
1.在java中可以用priority queue实现堆,默认最小堆,用Collections.reverseOrder可以建一个最大堆;
2.在java中ArrayList自带的有二分方法:Collections.binarySearch(),这个方法的时间复杂度是O(log(n)),不知道为什么比自己写的快,特别注意它的返回值:
Returns: the index of the search key, if it is contained in the list;
otherwise, (-(insertion point) - 1).
The insertion point is defined as the point at which the key would be inserted into the list: the index of the first element greater than the key, or list.size() if all elements in the list are less than the specified key. Note that this guarantees that the return value will be >= 0 if and only if the key is found.
即当没有找到元素时,它返回return = (-(insertion point) - 1),insertion point就是第一个比找不到的元素大的元素的索引,即这个元素可以插入的位置,那么我们解出insertion point = -return-1,就是插入元素的位置了。
3.BufferedReader还是比Scanner节省不少时间的,以后尽量用它。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了