Leetcode 刷题笔记(十一) —— 栈与队列篇之 top-K 问题

本文探讨了如何使用二分法、双指针和优先队列(堆)解决LeetCode中的两个经典问题:215.数组中的第K个最大元素和347.前K个高频元素。通过实例解析了大根堆和小根堆的应用,以及如何利用这些数据结构优化查找和频次统计。
摘要由CSDN通过智能技术生成

系列文章目录

一、 数组类型解题方法一:二分法
二、数组类型解题方法二:双指针法
三、数组类型解题方法三:滑动窗口
四、数组类型解题方法四:模拟
五、链表篇之链表的基础操作和经典题目
六、哈希表篇之经典题目
七、字符串篇之经典题目
八、字符串篇之 KMP
九、解题方法:双指针
十、栈与队列篇之经典题目


前言

刷题路线来自 :代码随想录
优先级队列(堆):堆可分为大根堆小根堆,以是数组形式的完全二叉树储存

大根堆
根结点 > 子结点,并且在堆的每一个局部都是如此。如 {3,1,2} 和 {3,2,1} 都为大根堆,大根堆的根结点在整个堆中是最大的元素。

小根堆
根结点 < 子结点。如{ 1,2,3} 和 {1,3,2} 都是小根堆。小根堆的根结点在整个堆中是最小的元素。

题录

215. 数组中的第K个最大元素

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

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

示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
题解:
先建一个大根堆,这样第一个数就为最大的数,然后每次和最后一个数交换位置,有效长度减一,再次向下调整为大堆。

class Solution {
    public int findKthLargest(int[] nums, int k) {
    	// 1.建大堆
        int end = nums.length - 1;
        for (int i = (end - 1) / 2; i >=0; i--) {
        	// 从最后一个非子叶结点开始向下调整
            adjustDown(nums, i,end);
        }
        // 每次去掉一个最大数
        while (k-- > 1) {
        	// 与最后一个数交换位置
            swap(nums, 0, end);
            // 有效长度减一
            end--;
            // 向下调整为大堆
            adjustDown(nums, 0, end);
        }
        return nums[0];
    }
    // 向下调整
    private void adjustDown(int[] array, int parent, int end) {
        // 1.找到最大子节点
        int child = 2 * parent + 1;  // 左孩子
        while (child <= end) {
        	// 找到最大孩子结点
            if (child + 1 <= end && array[child + 1] > array[child]) {
            	// 有右孩子,并且右大于左
                child += 1;
            }
            // 最大孩子结点大于父亲结点,交换位置
            if (array[child] > array[parent]) {
                swap(array, child, parent);
                parent = child;
                child = 2 * parent + 1;
            } else {
            	// 已经是大堆,不用调整了
                break;
            }
        }
    }
    // 交换
    private void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

347. 前 K 个高频元素

Leetcode 链接
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:
输入: nums = [1], k = 1
输出: [1]
题解: map 记录数组中数字出现次数,使用优先队列(堆),建小堆,遍历 map 依次添加元素进队列,如果队列满了(最大长度 k),出现次数最小的数(队列头元素)出队列
关于怎么确定确定优先级队列比较方法 【(o1, o2) -> o1.getValue() - o2.getValue() 的意思】,看上篇文章:链接
map的遍历:链接

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        int[] res = new int[k];
        // map 记录数组中数字出现次数
        Map<Integer, Integer> map = new HashMap<>();
        for (int num : nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }
        // 优先级队列(小根堆)
        PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) -> o1.getValue() - o2.getValue());
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            queue.add(entry);
            if (queue.size() > k) {
                queue.poll();
            }
        }
        // 填充返回组中
        for (int i = 0; i < k; i++) {
            res[i] = queue.poll().getKey();
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值