算法-再探无序数组中位数问题

算法-再探无序数组中位数问题

算法-再探无序数组中位数问题

给定一个无序数组,求无序数组的中位数

本问题在前面写的博客里面提到过算法-TopK相关的问题 。可以用堆实现或者用快速选择算法实现。在使用快速选择算法实现时,分为两种情况讨论,一种是数组元素数量为奇数时,我们直接选择中间元素即可,另一种是数量为偶数时,我们做两次快速选择。

但上述方法中,在数组元素数量为偶数时,并没有关注到第一次快速选择对数组的影响,导致第二次快速选择的时间复杂度可能达到O(N^2)

事实上,在我们可以利用快速选择的性质,将第二次选择时间复杂度降低到O(k-1)

快速选择的原理就是将枢纽元调整到位置k-1处,最终,枢纽元左边的元素大于等于枢纽元且右边元素小于等于枢纽元,或者反之。

在我们选出第k大的元素时,实际上,我们就能确定第k-1大的元素在枢纽元的左半部分或者是右半部分。

以选择第K大的元素为例,我们将数组按降序选择。

1、在数组长度为偶数时,我们需要选择第nums.length/2+1大的元素(记为m1),以及nums.length/2大的元素(记为m2)。在我们选择出m1,我们就可以确定,m2在k-1的左半部分,又因为左半部分全都大于m1,因此,问题变成求[0,k-1)区间的最小值,也就是m2,我们直接遍历区间的元素找最小值m2即可。最终的结果就是(m1+m2)/2。

2、在数组长度为奇数时,我们直接选择第nums.length/2+1大的元素(记为m1),m1就是我们要找的中位数

如此,我们就可以得到一份更快更简单的代码:

    @Test
    public void test(){
    
    
        int[] nums={
    
    7,5,9,3,11,32,27,1,-9,4};
        //-9,1,3,4,5,7,9,11,27,32
        System.out.println(mediumNUmberOfMixArray(nums));
    }


    public int mediumNUmberOfMixArray(int[] nums){
    
    
        int k=nums.length/2+1;
        quickSelect(nums,0,nums.length-1,k);
        int m1=nums[k-1];
        if(nums.length%2==1){
    
    
            return m1;
        }else {
    
    
            int m2=Integer.MAX_VALUE;
            for (int i=0;i<k-1;i++){
    
    
                m2=Math.min(m2,nums[i]);
            }
            return (m1+m2)/2;
        }

    }
    public void quickSelect(int[] nums,int left,int right,int k){
    
    
        if(left<right){
    
    
            int i=left,j=right;
            int pivot=nums[left];
            while (i<j){
    
    
                while (i<j&&nums[j]<=pivot){
    
    
                    j--;
                }
                while (i<j&&nums[i]>=pivot){
    
    
                    i++;
                }
                if(i<j){
    
    
                    swap(nums,i,j);
                }
            }
            swap(nums,i,left);//恢复枢纽元
            if(i>=k){
    
    
                quickSelect(nums,left,i-1,k);
            }else {
    
    
                quickSelect(nums,i+1,right,k);
            }
        }
    }

    private void swap(int[] nums, int i, int j) {
    
    
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }

猜你喜欢

转载自blog.csdn.net/qq_23594799/article/details/107594626