精华内容
下载资源
问答
  • 主要介绍了python 实现在无序数组中找到中位数方法,具有很好对参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 题目:利用快排思想一个无序数组中位数 对于一个有序数组arr来说: 如果数组长度为奇数,中位数为中间的那个数,即arr[arr.length/2] 如果数组长度为偶数,中位数为中间的两个数的平均值,即(arr[length/2] + ...

    题目:利用快排思想求一个无序数组的中位数

    对于一个有序数组arr来说:

    • 如果数组长度为奇数,中位数为中间的那个数,即arr[arr.length/2]
    • 如果数组长度为偶数,中位数为中间的两个数的平均值,即(arr[length/2] + arr[length/2-1]) / 2

    那么对于一个无序数组来说,应该如何求它的中位数 ?

    这个问题可以抽象化为寻找第k大的数,具体到寻找中位数,可分为两种情况:

    • 如果数组长度为奇数,即为寻找第arr.length/2大的数;
    • 如果为偶数,则为分别寻找第arr.length/2+1和第arr.length/2大的数,然后求其平均值。

    我们可以使用快排思想快速找中位数,即先挑选一个数作为标准(pivot),以该元素为支点,将数组划分为两部分。快排每排完一轮之后左侧都是比它小的元素,右侧都是比它大的元素,那么支点的index(假设为N-1)即为第N大的数。当N== K,我们就找到了第K大的数;当N > K时, 第K大的数在[0,N-1]范围内;当N < K时,第K大的数在[N+1,n-1](n为数组长度)范围内,利用递归即可找到第K大的数。

    注意:这里第k大的数,是下标为k-1的值,即arr[k-1]

    Java 实现如下:

    /**
     * 利用快排思想求无序数组中位数
     * @Author Hory
     * @Date 2020/9/8
     */
    public class Solution {
        /**
         * 寻找无序数组第k大的数,其实就是找排序后的数组的 arr[k-1]
         * 这里用到了递归
         * 明确函数意义:该方法实现了找到第k大的数,该方法没有返回值,通过不断调整数组,最终使得第k大的值位于索引k-1
         * @param arr
         * @param k
         * @param start
         * @param end
         * @return
         */
        private static void selectKthNum(int[] arr, int k, int start, int end){
            if(arr == null || k < 0 || start >= end) return;
            int left  = start;
            int right = end;
            int pivot = arr[start];
            while(left < right){
                while(left < right && arr[right] >= pivot) right--;
                arr[left] = arr[right];
                while(left < right && arr[left] <= pivot) left++;
                arr[right] = arr[left];
            }
            arr[left] = pivot;
            if(left == k) return;
            else if(left < k) selectKthNum(arr,k,left+1,end);
            else selectKthNum(arr,k,start,left-1);
        }
    
        /**
         * @param arr
         * @return
         */
        public static double findMedian(int[] arr){
            if(arr.length <= 0) return -1;
            int length = arr.length;
            if(length % 2 == 1) {  // 如果数组长度为奇数,只需返回中间的数字即可
                selectKthNum(arr,length/2,0,length-1);
                return arr[(length)/2];
            }else {   //如果数组长度为偶数,返回中间两个数字的平均值
                selectKthNum(arr,length/2-1,0,length-1);
                selectKthNum(arr,length/2,0,length-1);
                return (arr[length/2] + arr[length/2-1])/2.0;
            }
        }
    }
    
    展开全文
  • 找出无序数组中位数的方法

    千次阅读 2020-01-13 13:10:48
    今早上在LintCode上做到了这种类型的题目,题目要求找到无序数组中位数在数组的位置,一开始想到的是利用快排的思想来做,但是由于只有十五分钟的时间,就直接用最普通的方式做了,思路是map记录位置+sort排序,水...

    今早上在LintCode上做到了这种类型的题目,题目要求找到无序数组中位数在数组的位置,一开始想到的是利用快排的思想来做,但是由于只有十五分钟的时间,就直接用最普通的方式做了,思路是map记录位置+sort排序,水过去了。
    找无序数组中位数我想着我之前逛知乎的时候遇到过,用最大堆和最小堆来做的。想了想,遇到这么多次,那就整理下方法吧。

    这里中位数的定义是数组元素个数/2

    1 直接排序找中位数

    直接利用自带的sort方法排序,然后返回数组的中间索引的值
    代码如下:

        //1.直接排序
        public static int findMediaMethod1(int[] a)
        {
            if(a.length==0) return -1;
            Arrays.sort(a);
            return a[(a.length-1)/2];
        }
    

    第一种方法太暴力了,我们只需要中位数即可,而不需要对数组中所有的元素进行处理。
    这就引申出了第二种方法:

    2 利用快排思想

    快排的基本思想是选取一个哨兵元素,然后设立两个指针left,right,分别指向左端和右端,两个指针相向运动,当左右指针都遇到了违反数组次序的元素的时候左右指针交换元素(违反数组次序是指左指针找到了大于哨兵元素的元素或右指针找到了小于哨兵元素的值),这样当左右指针相遇的时候,左边的数组元素一定小于等于哨兵元素,右边的数组元素一定大于等于哨兵元素。我们可以利用这一性质来找中位数,每次进行快排操作后记录下哨兵元素的位置,如果大于中间元素的话,则我们只需要对左边进行快排操作,当小于中间元素,我们只需要对右边进行快排操作,跟二分查找很像。
    代码如下:

        //2.利用快排原理进行排序
        public static int findMediaMethod2(int[] a)
        {
            if(a.length==0) return -1;
            //中位数位置
            int mid=(a.length-1)/2;
            //左右指针位置
            int left=0,right=a.length-1;
            //进行快排操作后哨兵元素的位置
            int qsIdx=0;
            qsIdx = quickSort(left,right,a);
            while(true)
            {
                //System.out.println("qsIdx= "+qsIdx);
                if(qsIdx==mid)
                {
                    break;
                }
                else if(qsIdx<mid) qsIdx=quickSort(qsIdx+1,right,a);
                else qsIdx=quickSort(left,qsIdx-1,a);
            }
            return a[qsIdx];
        }
        public static int quickSort(int left,int right,int[] a)
        {
            int target=a[left];
            while(left<right)
            {
                while(left<right&&a[right]>=target) right--;
                a[left]=a[right];
                while(left<right&&a[left]<=target) left++;
                a[right]=a[left];
            }
            //System.out.println("left="+left);
            a[left]=target;
            return left;
        }
    

    3 利用大小堆性质

    第三种方法我是看的牛客网上的一个回答才会的。这里附上链接:
    点击这里
    大顶堆存数组中较小部分的元素,小顶堆存数组中较大部分的元素,相当于将数组分成两半了,这样
    大顶堆的堆顶或小顶堆的堆顶就是我们找的中位数。
    如何实现呢?
    1. 当插入堆中的元素个数为偶数时,将当前元素插入大顶堆,将大顶堆的堆顶元素插入小顶堆
    2. 当插入堆中的元素个数为奇数时,将当前元素插入小顶堆,将小顶堆的堆顶元素插入大顶堆
    hhh,是不是很神奇。
    代码如下:

     //3.利用大顶堆和小顶堆性质进行排序
        public static int findMediaMethod3(int[] a)
        {
            if(a.length==0) return -1;
            Queue<Integer> minHeap = new PriorityQueue<Integer>();
            Queue<Integer> maxHeap = new PriorityQueue<Integer>(new Comparator<Integer>() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    return o2-o1;
                }
            });
            for (int i=0;i<a.length;i++)
            {
                if(i%2==0)
                {
                    maxHeap.add(a[i]);
                    int top = maxHeap.poll();
                    minHeap.add(top);
                }
                else
                {
                    minHeap.add(a[i]);
                    int top = minHeap.poll();
                    maxHeap.add(top);
                }
            }
            return a.length%2==0? maxHeap.peek():minHeap.peek();
        }
    

    总结

    上面的三种方法,第一种肯定是不提倡的,第三种的话,因为一次操作就需要一次堆插入操作(log(m))(m表示堆中元素数目),n次操作的话就是nlog(m) ,第二种感觉的话应该是nlog(n)? 不过最官方的肯定是第三种方法。

    展开全文
  • 求无序数组中位数

    千次阅读 2018-10-02 21:35:01
    求无序数组中位数,我们首先想到的是将该数组进行排序,然后找到中间的元素,但是往往面试的时候,面试官就会怼你,说你时间复杂度太高了....要你优化(个人感觉,面试官对你问了问题,有一个自己的标准,如果你答...

    求无序数组的中位数,我们首先想到的是将该数组进行排序,然后找到中间的元素,但是往往面试的时候,面试官就会怼你,说你时间复杂度太高了....要你优化(个人感觉,面试官对你问了问题,有一个自己的标准,如果你答不到他的点子上,他就不满意,各种怼,直到你想到他的标准,否则,挂掉),针对上面的问题,用一下两种方法求解

     

    1 先排序后取中间值:

    注意:python 3里面的运算符:"//":取整  "/" :真除法   "~":按位取反运算符:对数据的每个二进制位取反,即把1变为0,把0变为1 。~x类似于 -x-1

    def get_middle(array):
        array.sort()
        index = len(array)//2
        return (array[index]+array[~index])/2
    
    print(get_middle([2,1,5,8,3,9,4]))
    print(get_middle([2,1,5,8,3,9,4,6]))

    2 通过构建最小堆来求解

    思想是:

    1 对无序数组的前len(array)//2长度的元素建立最小堆,这样就得到了一个堆顶元素小于任意一个堆里的元素

    2 将剩下的一半元素依次与堆顶元素比较。若比堆顶元素大,则替换之,并调整堆。(也就是说:依次遍历剩下一般的元素,与当前的堆顶元素作比较,如果大于堆顶元素,则替换,这时,重新调整堆的结构,使其保持为最小堆,否则,遍历下一个元素,知道剩下的一半元素遍历结束)

    3 数组剩下的所有元素比较完后,可以输出中位数。数组长度为奇数时,输出堆顶元素即可。数组长度为偶数时,输出堆顶元素与它的孩子结点中较小的那个的均值。

    def heap_adjust(parent,heap):   #更新结点后进行调整
        child=2*parent+1
        while len(heap)>child:
            if child+1<len(heap) and heap[child+1]<heap[child]:
                child+=1
            if heap[parent]<=heap[child]:
                break
            heap[parent],heap[child]=heap[child],heap[parent]
            parent,child=child,child*2+1
     
    def find(nums):
        k=len(nums)//2 +1
        heap=nums[:k]
        for i in range(k,-1,-1):   #前n/2个元素建堆
            heap_adjust(i,heap)
        for j in range(k,len(nums)):
            if nums[j]>heap[0]:
                heap[0]=nums[j]
                heap_adjust(0,heap)
        #奇数时是最中间的数,偶数时是最中间两数的均值
        return heap[0] if len(nums)%2==1 else float(heap[0]+min(heap[1],heap[2]))/2
     
    print(find([1,2,8,9,3,5,4,6,7,0]))
    print(find([1,3,2,4])

    展开全文
  • 求无序数组中位数(c语言版本)

    千次阅读 2019-03-22 16:06:41
    在面试时,会经常被问道,如何求解一个无序数组中位数?很多人往往都会第一感觉就是,先将该数组排序,然后找出最中间的那个数,但是这种思路通常的时间复杂度最好是O(nlogn),更糟的情况下会到O(n^2),并不是最优...

    在面试时,会经常被问道,如何求解一个无序数组的中位数?很多人往往都会第一感觉就是,先将该数组排序,然后找出最中间的那个数,但是这种思路通常的时间复杂度最好是O(nlogn),更糟的情况下会到O(n^2),并不是最优解,也就不能impressed面试官了。下面我们聊聊这个话题。

    何为中位数?

    中位数,就是数组排序后位于数组最中间位置的那个元素。当然,细分析的话,还要区分该数组的长度,如果该数组长度为n,若n为奇数,则中位数就是(n+1)/2位置上的数;若n为偶数,则中位数是n/2和n/2+1位置上的两个数的平均值,这里我们为了简单起见,就用n/2位置上的数代替吧。

    现在我们考虑一个更一般的问题:

    如何求解一个无序数组的第k小的数?

    如果能求解出第k小的数,那么就能求出第k大的数(它对应第(n-k)+1小的数),特别地,如果k为n/2或(n+1)/2的话,这就是我们要求的中位数。

    关于这个问题,我发现在Allen Weiss的《数据结构与算法分析》一书中一直贯穿始终,特别是在第七章排序中,给出了时间复杂度为O(n)的解决方法,该解决方法,也就是一个"二分法"思想的快速排序思想的变体,但是比快速排序的实现更快更简单,因为它只需要对牵涉范围的那些子数组排序。

    下面是我的源码实现,以作备忘。

    //description: 查找无序数组中指定的第k小的数
    //date: 2019-03-21
    
    #include <stdio.h>
    #include <stdlib.h>
    
    void swap(int arr[], int a, int b){
        int tmp = arr[a];
        arr[a] = arr[b];
        arr[b] = tmp;
    }
    
    void quick_select(int arr[], int k, int s, int e){
        if(s > e || k < s || k > e){
            printf("invalid array range\n");
            return;
        }
    
        //这里随机将左边第一个元素设置为基准点
        int i, j, pivot = arr[s];
        if(s <= e){
            i = s;
            j = e;
            for(;;){
                while(arr[j] >= pivot && i<j){j--;}
                while(arr[i] <= pivot && i<j){i++;}
                if(i<j)
                    swap(arr, i, j);
                else
                    break;
            }
            //恢复pivot
            swap(arr, i, s);
    
            //继续进行下一轮迭代
            if(k<=i)
                quick_select(arr, k, s, i-1);
            else if(k>=i+1)
                quick_select(arr, k, i+1, e);
        }
    }
    
    //数组复制
    void copy_array(int arr[], const int barr[], int n){
        int i = 0;
        for(i=0; i<n; i++)
            arr[i] = barr[i];
    }
    
    int main(int argc, char** argv){
        int a[] = {12,4,3,67,900,22,28,9,61,53,23,12};
        int n = sizeof(a) / sizeof(int);
        int k = 4;
    
        int b[n];
        copy_array(b, a, n);
        int m = n%2==0 ? n/2 : (n+1)/2;
    
        //求第k小的数
        quick_select(a, k, 0, n-1);
        printf("the %d-th smallest number: %d\n", k, a[k-1]);
    
        for(int i=0; i<n; i++)
            printf("%d ", a[i]);
        printf("\n");
    
        //求解中位数
        quick_select(b, m, 0, n-1);
        printf("the median nuber(%d-th): %d\n", m, b[m-1]);
    
        for(int i=0; i<n; i++)
            printf("%d ", b[i]);
        printf("\n");
    
        return 0;
    }

    这里给出了求解第4小和第6小的数的排序,因为数组长度为12,我就把6当做是该数组的中位数了。

    运行截图如下:

     

    展开全文
  • 求无序数组当中的中位数(快排思想,选中关键字,高低交替扫描) 示例: [@"1",@"9",@"6",@"8",@"3",@"2"] 输出: @"3" */ + (void)findMedianValue { NSMutableArray *array = [NSMutableArray ...
  • 无序数组求中位数

    千次阅读 2018-12-07 16:34:46
    长度为 n 的无序数组求中位数,如何尽快的估算出中位数,算法复杂度是多少? 算法 1(建立最小堆): 如果数组中元素有奇数个,可以采用这种算法: 步骤 1 :可以将数组的前 (n+1)//2 个元素,建立 1 个最小堆; ...
  • 基本思路:对数组进行排序,直接访问数组中位数 double MIDnum(vector<int>& array) { if(array.empty()) return -1; int midIndex = (array.size() - 1) / 2; sort(array.begin(), array.end()); if...
  • 无序数组中位数

    2021-04-04 09:27:11
    1.无序数组中位数 思路一 把无序数组排好序,取出中间的元素 时间复杂度 采用普通的比较排序法 O(N*logN) 如果采用非比较的计数排序等方法, 时间复杂度 O(N), 空间复杂度也是O(N). 思路二 (1)将前(n+1)/2个...
  • 寻找无序数组中位数

    千次阅读 2017-08-06 22:13:40
    题目:一个无序数组中位数。 如:{2,5,4,9,3,6,8,7,1}的中位数为5,{2,5,4,9,3,6,8,7,1,0}的中位数为4和5。 要求:不能使用排序,时间复杂度尽可能高 提示:考虑堆或者快排思想解决。
  • 一,问题描述1,一个无序数组中位数, (若数组是偶数,则中位数是指中间两个数字之和除以2,若数组是奇数,则中位数是指最中间位置。要求:不能使用排序,时间复杂度尽量低2, 例如:lists = [3, 2, 1, 4] , ...
  • 给一个无序数组array和数组长度n,找出其中的中位数(这里考虑n为奇数) Sample: ***** Input: ***** @[@(500),@(120),@(7),@(220),@(3),@(8),@(4),@(200),@(100) ***** Output: ***** 100 解法一:将数组...
  • 一个无序数组中位数(Python)

    千次阅读 2018-07-12 10:31:17
    最简单的方法是先将数组排序,然后找中位数。但此种方法肯定不是最优的。一个比较好的做法是利用小顶堆。思路如下:1.取前len(nums)/2个元素建立小顶堆。可以知道堆顶元素是前len(nums)/2个元素中最小的。2.从第len...
  • 一个无序数组中位数

    千次阅读 2017-08-08 23:37:29
    一个无序数组中位数。 如:{2,5,4,9,3,6,8,7,1}的中位数为5。 要求:不能使用排序。 暂时只考虑奇数时的情况,偶数有时会规定相邻两个数的平均数。 下面的分析都只考虑奇数的情况。 思路1:对前(n+1)/2个...
  • 求数组中位数

    2020-02-17 20:20:44
    求无序数组第K大元素的算法,有两种思路: 方法1:暴力法,通过最数组元素排序,找到第K大元素。 方法2: 利用快排的思想,对整个数组元素分组。任意挑一个元素,以该元素key,划分数组为两部分,key左边元素小于...
  • 1. 选取第一个元素为基数,分别从右(high)往左(high--)查找,找到一个比基数小的,进行位置交换, 直到 low == high,结束一次排序;然后从 左 往右查找,找到一个比基数大的,进行位置交换,直到 low == ...
  • 无序数组中求中位数

    千次阅读 2017-06-08 16:34:15
    题目现有一些随机生成的数字要将其...给定一个int数组A,为传入的数字序列,同时给定序列大小n,请返回一个int数组,代表每次传入后的中位数。保证n小于等于1000。 测试样例:[1,2,3,4,5,6],6 返回:[1,1,2,2,3,3]思
  • 【算法】无序数组中求中位数

    千次阅读 2017-10-05 11:23:31
    一个无序数组中位数。 如:{2,5,4,9,3,6,8,7,1}的中位数为5。 要求:不能使用排序,时间复杂度O(n)。 分析因为题目指定不能使用排序算法,而且要求时间复杂度O(n),也就是要求一次遍历就得给出结果。所以排序...
  • 中位数,就是数组排序后处于数组最中间的那个元素。...思路1:将数组排序,然后直接从排序数组中找出中位数。时间复杂度取决于排序算法,最快是快速排序,O(nlogn),或者是非比较的基数排序,时间为O(n),空间为O...
  • 无序数组中位数可以快排,然后直接去array[mid]即可,但这确实还不够快,因为我们的任务是找到中位数,而没有说要对这个数组排序,即只要array[mid]是中位数即可,array[0…mid]之间数据可以是无序的,只要小于...
  • 无序数组中位数

    2020-09-01 21:28:31
    面试时,大家是不是经常被问到,怎么一个无序数组(长度为n)的中位数? 不假思索的算法是,首先将数组排序,然后直接从排序数组中找出中位数。这个算法的复杂度是O(nlogn),就是排序的复杂度。当然,答案是有了...
  • * 一个无序数组中位数。 * 如:{2,5,4,9,3,6,8,7,1}的中位数为5。 要求:不能使用排序,时间复杂度O(n)。 */ int [] array = {1,2,3,4,49,55,6,7,80,100};//{2,5,4,9,3,6,8,7,1}; @Test public void ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 46,507
精华内容 18,602
关键字:

求无序数组的中位数