Plantre Plantre
首页
后端
技术
硬件
  • 前端文章

    • HTML
    • CSS
    • JavaScript
  • 技术

    • 技术文档
    • GitHub技巧
    • Nodejs
    • 博客搭建
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

plantre

一个后端开发者
首页
后端
技术
硬件
  • 前端文章

    • HTML
    • CSS
    • JavaScript
  • 技术

    • 技术文档
    • GitHub技巧
    • Nodejs
    • 博客搭建
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 计算机组成原理

  • 操作系统

  • 计算机网络

  • 设计模式

  • Java

  • Spring

  • SpringCloud

  • MySQL

  • Redis

  • 分布式

  • Zookeeper

  • Dubbo

  • Kafka

  • 数据结构

  • 算法

  • OJ

    • 自定义
    • 排序
      • 位运算
      • 二分查找
      • 递归
      • 双指针(逆向,快慢)
      • 滑动窗口
      • 辅助栈
      • 贪心
      • 回溯
      • 动态规划
      • 二叉树
      • DFS
      • 拼接&拆分
    • 从道家哲学看计算机?
    • 后端
    • OJ
    plantre
    2025-06-11
    目录

    排序

    # 215. 数组中的第K个最大元素 - 力扣(LeetCode) (opens new window)

    # 暴力

    时间:O(N logN),Java的Arrays.sort()底层采用双基准快排优

    空间:O(1)

    public int findKthLargest(int[] nums, int k) {
        Arrays.sort(nums);
        return nums[nums.length - k];
    }
    
    1
    2
    3
    4
    # 快速选择

    时间:平均O(N),最坏O(N²)(可通过随机化基准值优化)

    空间:O(logN)(递归栈开销)

    public int findKthLargest(int[] nums, int k) {
        return quickSelect(nums, 0, nums.length - 1, nums.length - k);
    }
    
    private int quickSelect(int[] nums, int left, int right, int target) {
        int pivotIndex = partition(nums, left, right);
        if (pivotIndex == target) {
            return nums[pivotIndex];
        } else if (pivotIndex < target) {
            return quickSelect(nums, pivotIndex + 1, right, target);
        } else {
            return quickSelect(nums, left, pivotIndex - 1, target);
        }
    }
    
    // 随机化基准的分区函数(Lomuto方案)
    private int partition(int[] nums, int left, int right) {
        int randomIndex = left + (int)(Math.random() * (right - left + 1));
        swap(nums, randomIndex, right);
        int pivot = nums[right];
        int i = left - 1;
        for (int j = left; j < right; j++) {
            if (nums[j] <= pivot) {
                i++;
                swap(nums, i, j);
            }
        }
        swap(nums, i + 1, right);
        return i + 1;
    }
    
    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    # 堆排序(优先队列)

    时间:O(N logk),每次插入/弹出堆顶的时间为O(logk)

    空间:O(k)

    // 使用PriorityQueue(默认小顶堆)
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> heap = new PriorityQueue<>();
        for (int num : nums) {
            heap.offer(num);
            if (heap.size() > k) {
                heap.poll();
            }
        }
        // pq 中剩下的是 nums 中 k 个最⼤元素,
        // 堆顶是最⼩的那个,即第 k 个最⼤元素
        return heap.peek();
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 原地堆排序优化

    时间:O(N logk),但常数更优(省去PriorityQueue的封装开销)

    空间:O(1)

    public int findKthLargest(int[] nums, int k) {
        // 构建初始小顶堆(前k个元素)
        for (int i = (k - 2) / 2; i >= 0; i--) {
            heapify(nums, i, k);
        }
        // 遍历剩余元素并调整堆
        for (int i = k; i < nums.length; i++) {
            if (nums[i] > nums[0]) {
                swap(nums, 0, i);
                heapify(nums, 0, k);
            }
        }
        return nums[0];
    }
    
    private void heapify(int[] nums, int parent, int heapSize) {
        int left = 2 * parent + 1;
        while (left < heapSize) {
            int minChild = (left + 1 < heapSize && nums[left] > nums[left + 1]) ? left + 1 : left;
            if (nums[parent] <= nums[minChild]) break;
            swap(nums, parent, minChild);
            parent = minChild;
            left = 2 * parent + 1;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    # 计数排序

    时间:O(N + M),M为数值范围(本题M=2e4)

    空间:O(M)

    public int findKthLargest(int[] nums, int k) {
        int[] count = new int[20001];
        for (int num : nums) {
            count[num + 10000]++; // 处理负数
        }
        int sum = 0;
        for (int i = count.length - 1; i >= 0; i--) {
            sum += count[i];
            if (sum >= k) {
                return i - 10000;
            }
        }
        return -1;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    编辑 (opens new window)
    上次更新: 2025/06/13, 00:51:28
    自定义
    位运算

    ← 自定义 位运算→

    最近更新
    01
    集成loki
    07-04
    02
    TCP的ESTABLISHED是什么意思
    06-24
    03
    安装1panel
    06-24
    更多文章>
    Theme by Vdoing | Copyright © 2025-2025 plantre | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式