滑动窗口的中位数 LintCode.com
-
题目:给定一个包含 n 个整数的数组,和一个大小为 k 的滑动窗口,从左到右在数组中滑动这个窗口,找到数组中每个窗口内的中位数。(如果数组个数是偶数,则在该窗口排序数字后,返回第 N/2 个数字。
- 样例
对于数组 [1,2,7,8,5], 滑动大小 k = 3 的窗口时,返回 [2,7,7]
最初,窗口的数组是这样的:
[ | 1,2,7 | ,8,5] , 返回中位数 2;
接着,窗口继续向前滑动一次。
[1, | 2,7,8 | ,5], 返回中位数 7;
接着,窗口继续向前滑动一次。
[1,2, |7,8,5 | ], 返回中位数 7;
- 算法:
我的算法利用了冒泡排序的思想,用一个数组存储滑动窗口里的元素,并且时刻保持这个数组有序。在窗口滑动后,用二分查找法找到移出窗口的元素在这个数组的位置,然后将移入窗口的元素加入这个位置,通过与前面或后面的元素多次比较移动使数组重新有序(冒泡排序的思想)。
时间复杂度:O(n)= n(log(n)+n) = n*n;
ps:网上有利用堆来实现的,但是对于我来说很难想到,经过测试我的代码所用时间和利用堆来实现的是差不多的。(虽然它的时间复杂度好像是n*log n)。
另外,新手写博客,有做的不好的地方请留言。
Java 源代码:
1 public static ArrayList<Integer> medianSlidingWindow(int[] nums, int k) { 2 ArrayList<Integer> list = new ArrayList<Integer>(); 3 if(k==0||nums==null) //窗口大小为0或数组为空则返回null; 4 return null; 5 int[] temp = new int[k]; //用来存储滑动窗口的元素,并且排序。 6 for(int i=0;i<k;i++) //先初始化temp; 7 temp[i] = nums[i]; 8 Arrays.sort(temp); //用Java内置方法对数组排序。 9 list.add(temp[(k-1)/2]); //获得第一个滑动窗口的中位数 10 int left = 0; //滑动窗口的左边。 11 int right = k-1; //滑动窗口的右边。 12 /* 13 * 窗口开始滑动 14 */ 15 while(right<nums.length-1){ 16 int index = Arrays.binarySearch(temp, nums[left++]); //用二分查找找到滑出的元素在temp的位置。 17 temp[index] = nums[++right]; //将划入的元素放在滑出的元素的位置上。 18 while(index>0){ // index》0 表示元素向左移有位置。 19 if(temp[index]<temp[index-1]){ //如果元素左边的元素大于他,则向左移,否则直接退出循环。 20 int t = temp[index]; 21 temp[index] = temp[index-1]; 22 temp[index-1] = t; 23 index--; 24 }else 25 break; 26 } 27 while(index<k-1){ // index《k-1 表示元素向右移有位置。 28 if(temp[index]>temp[index+1]){ //如果元素右边的元素小他,则向右移,否则直接退出循环。 29 int t = temp[index]; 30 temp[index] = temp[index+1]; 31 temp[index+1] = t; 32 index++; 33 }else 34 break; 35 } 36 list.add(temp[(k-1)/2]); 37 } 38 return list; 39 }