快排衍生之「利用快排思想求无序数组中位数」

news/2024/5/19 23:23:49 标签: 数据结构, 算法, 快速排序, leetcode

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

对于一个有序数组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;
        }
    }
}

http://www.niftyadmin.cn/n/1690312.html

相关文章

Java:FocusListener接口

有了ActionListener事件监听器&#xff0c;就一定要有FocusListener焦点事件监听器。 FocusListener接口所在包 FocusListener接口在event包中&#xff0c;即在开头引入该包。 import java.awt.event.*;FocusListener接口使用方法 先说一下什么叫焦点监听器。焦点监听器其实…

剑指Offer系列之「把数组排成最小的数」

把数组排成最小堆的数 输入一个正整数数组&#xff0c;把数组里所有数字拼接起来排成一个数&#xff0c;打印能拼接出的所有数字中最小的一个。例如输入数组{3&#xff0c;32&#xff0c;321}&#xff0c;则打印出这三个数字能排成的最小数字为 321323。 这道题需要用到比较器 …

Python:注释

Python中的注释方法跟C和Java还是又些许区别的。 单行注释 单行注释以 # 开头&#xff0c;语法如下&#xff1a; # 注释内容"#"后面的内容都被Python编辑器所忽略。 多行注释 多行注释的话&#xff0c;就是以三个引号为开头行&#xff0c;又以三个引号为结尾行&…

剑指Offer系列之「复杂链表的复制」

请实现 copyRandomList 函数&#xff0c;复制一个复杂链表。在复杂链表中&#xff0c;每个节点除了有一个 next 指针指向下一个节点&#xff0c;还有一个 random 指针指向链表中的任意节点或者 null。 将链表进行拓展&#xff0c;在每个链表结点的旁边拷贝&#xff0c;比如 A-&…

算法:强连通分量缩点

有时对于一个有向图我们及其渴望将其变为一个有向无环图&#xff0c;这样我们就要用到强连通分量缩点了。 例题 洛谷3387 缩点 题目背景 缩点DP。 题目描述 给定一个 n个点 m条边有向图&#xff0c;每个点有一个权值&#xff0c;求一条路径&#xff0c;使路径经过的点权值之…

MySQL启动不成功,一直运行

Mysql 启动不成功&#xff0c;一直在执行中&#xff0c;最终报错&#xff1a; The server quit without updating PID file 执行 mysql.server restart 进行重启&#xff0c;报错&#xff1a; ERROR! MySQL server PID file could not be found! 原因分析 通常出现这种情况是由…

剑指Offer系列之「调整数组顺序使奇数位于偶数前面」

方法一&#xff1a;使用辅助数组 开辟一个新的数组&#xff0c;数组长度跟原数组相同 第一次遍历原数组&#xff0c;将奇数依次添加到新数组中&#xff1b; 第二次遍历原数组&#xff0c;从上次添加之后的末尾位置开始&#xff0c;将偶数依次添加到新数组中。 然后新数组的…

剑指Offer系列之「链表中倒数第 k 个节点」

方法一&#xff1a;普遍解法 首先先遍历链表&#xff0c;求得链表的长度 len 链表的倒数第k个节点&#xff0c;其实就是正向索引为len-k的节点 此外需要考虑k的值&#xff0c;当k的值大于链表的长度&#xff0c;返回null 时间复杂度&#xff1a;O(n)&#xff0c;需要遍历数组…