求数组中的第K个最大元素

69 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第14天,点击查看活动详情

1、前言

每天一个算法小练习,本篇使用Java实现。

2、题目描述

  给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

  • 1 <= k <= nums.length <= 105
  • -104 <= nums[i] <= 104

2.1、示例1

输入: [3,2,1,5,6,4], k = 2
输出: 5

2.2、示例2

输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

3、解题思路

3.1、快排

快速排序是一种既高效,又不怎么浪费空间的排序算法。它以选中的基准数来进行多次的比较与交换来完成排序。这个过程由多次重复单趟排序组成,可以把它理解为冒泡排序+递归分治。对于每一次单趟排序:选中一个基准数 k,让 k 的左边的所有数小于 k,k 的右边都大于 k。那么对于 k 来说,它已经被排好序了。下面就对 k 的左右两边进行上述操作,每次排序好一个基准数,最终整个数组就是有序的。

public int findKthLargest(int[] nums, int k) {
    return quickSort(nums, 0, nums.length - 1, k);
}

/**
    * 快排
    * @param nums
    * @param left
    * @param right
    * @param k
    * @return
    */
public int quickSort(int[] nums, int left, int right, int k){
    while(left <= right){
        int mid = partition(nums,left,right);
        // 数组长度 - k = 第K个最大元素的索引
        int target = nums.length - k;
        if(mid == target){
            return nums[mid];
        }else if(mid < target){
            left = mid + 1;
        }else {
            right = mid - 1;
        }
    }
    return -1;
}

public int partition(int[] nums, int left, int right){
    int pivot = nums[right];
    while(left < right){
        while(left < right && nums[left] <= pivot){
            left++;
        }
        if(left < right){
            swap(nums,left,right);
            right--;
        }
        while(left < right && nums[right] >= pivot){
            right--;
        }
        if(left < right){
            swap(nums,left,right);
            left++;
        }
    }
    return left;
}

/**
    * 交换值
    * @param nums
    * @param left
    * @param right
    */
public void swap(int[] nums, int left, int right){
    int temp = nums[left];
    nums[left] = nums[right];
    nums[right] = temp;
}

执行结果:

image.png

  • 时间复杂度:O(N)O(N)

  • 空间复杂度:O(1)O(1)

好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊