【算法】【线性表】【数组】数组中的第K个最大元素

1  题目

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

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

示例 2:

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

提示:

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

2  解答

刚开始我这么想的,直接快速排序:

复制代码
class Solution {
    public int findKthLargest(int[] nums, int k) {
        // 直接点 直接排序 排完直接返回 nums[k]
        quickSort(nums, 0, nums.length - 1);
        return nums[k - 1];    
    }

    public void quickSort(int[] nums, int start, int end) {
        if (start > end) {
            return;
        }

        int leftIndex = start;
        int rightIndex = end;
        int temp = nums[leftIndex];

        while (leftIndex < rightIndex) {
            while (leftIndex < rightIndex && nums[rightIndex] <= temp) {
                rightIndex--;
            }
            while (leftIndex < rightIndex && nums[leftIndex] >= temp) {
                leftIndex++;
            }
            if (leftIndex < rightIndex) {
                nums[leftIndex] = nums[leftIndex] ^ nums[rightIndex];
                nums[rightIndex] = nums[leftIndex] ^ nums[rightIndex];
                nums[leftIndex] = nums[leftIndex] ^ nums[rightIndex];
            }
        }
        nums[start] = nums[leftIndex];
        nums[leftIndex] = temp;

        // 递归
        quickSort(nums, start, rightIndex - 1);
        quickSort(nums, rightIndex + 1, end);
    }
}
复制代码

可是超时了,看来人家并不想我这么直接:

那么我们改一下快速排序,基于快速排序的特点是先找位置,然后再排位置的左边和右边,因为要找第 K 个,也就是说我没必要把所有的都排好,当我排到第K 个的时候,就可以停了,那我主要改了两个地方(下边有注释的两个地方):

复制代码
class Solution {
    public int findKthLargest(int[] nums, int k) {
        // 直接点 直接排序 排完直接返回 nums[k]
        quickSort(nums, 0, nums.length - 1, k - 1);
        return nums[k - 1];    
    }

    public void quickSort(int[] nums, int start, int end, int target) {
        if (start > end) {
            return;
        }

        int leftIndex = start;
        int rightIndex = end;
        int temp = nums[leftIndex];

        while (leftIndex < rightIndex) {
            while (leftIndex < rightIndex && nums[rightIndex] <= temp) {
                rightIndex--;
            }
            while (leftIndex < rightIndex && nums[leftIndex] >= temp) {
                leftIndex++;
            }
            if (leftIndex < rightIndex) {
                nums[leftIndex] = nums[leftIndex] ^ nums[rightIndex];
                nums[rightIndex] = nums[leftIndex] ^ nums[rightIndex];
                nums[leftIndex] = nums[leftIndex] ^ nums[rightIndex];
            }
        }
        nums[start] = nums[leftIndex];
        nums[leftIndex] = temp;
        // 如果中间元素的位置就刚好等于第 K 个了 说明已经找到了,就不需要排序别的了
        if (leftIndex == target) {
            return;
        }

        // 递归
        // 根据 target 和 rightIndex 的大小来判断是排序左边还是右边
        if (rightIndex >= target) {
            quickSort(nums, start, rightIndex - 1, target);
        } else {
            quickSort(nums, rightIndex + 1, end, target);
        }
    }
}
复制代码

哈哈哈,通过了,这个时间貌似有点拉跨啊,排到最后一名了都。对这种 TopK的问题,堆排序我再试试:

复制代码
class Solution {
    public int findKthLargest(int[] nums, int k) {
        // 调整 k 次
        for(int i = 0; i < k; i++) {
            // 先构造最大堆
            adjustHead(nums, nums.length - i);
            // 然后交换
            swap(nums, 0, nums.length - i - 1);
        }
        return nums[nums.length - k];
    }

    /**
     * 调整堆
     * @param arr
     * @param length
     */
    public void adjustHead(int[] arr, int length) {
        // 从第一个非叶子节点开始
        for (int i = length / 2 - 1; i >= 0; i--) {
            // 左右选一个最大的
            int maxChildIndex = 2 * i + 1;
            if (maxChildIndex + 1 < length && arr[maxChildIndex + 1] > arr[maxChildIndex]) {
                maxChildIndex = maxChildIndex + 1;
            }
            // 如果儿子比爸爸大,那么就要交换  交换完继续向下调整
            if (arr[i] < arr[maxChildIndex]) {
                swap(arr, i, maxChildIndex);
                int sub = 2 * maxChildIndex + 1;
                while (sub < length) {
                    if (arr[sub] > arr[maxChildIndex]) {
                        swap(arr, sub, maxChildIndex);
                        sub = 2 * sub + 1;
                        continue;
                    }
                    if (sub + 1 >= length || arr[sub + 1] <= arr[maxChildIndex]) {
                        break;
                    }
                    swap(arr, sub + 1, maxChildIndex);
                    sub = 2 * sub + 1;
                }
            }
        }
    }

    public void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}
复制代码

= =,超时了尴尬。。。。。

是不是我写的堆排序,不太优雅。

posted @   酷酷-  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2023-03-25 【Spring MVC】请求处理过程
2023-03-25 【Spring MVC】创建过程
点击右上角即可分享
微信分享提示