【力扣hot100题】(073)数组中的第K个最大元素

花了两天时间搞明白答案的快速排序和堆排序。

两种都写了一遍,感觉堆排序更简单很多。

两种都记录一下,包括具体方法和易错点。

快速排序

cpp 复制代码
class Solution {
public:
    vector<int> nums;
    int quicksort(int left,int right,int k){
        if(left==right) return nums[k];
        int r=right;
        int mid=left;
        left--;right++;
        while(left<right){
            do left++; while(nums[left]<nums[mid]);
            do right--; while(nums[right]>nums[mid]);
            if(left<right) swap(nums[right],nums[left]);
        }
        if(right>=k) return quicksort(mid,right,k);
        else return quicksort(right+1,r,k);
    }
    int findKthLargest(vector<int>& nums, int k) {
        this->nums=nums;
        return quicksort(0,nums.size()-1,nums.size()-k);
    }
};

具体方案:定下首个元素的值为mid,设置双指针分别指向首个元素的前一位最后一个元素的后一位,当左指针在右指针左边时,移动左指针到第一个大于mid的位置,移动右指针到第一个小于mid的位置,若左指针在右指针左边,则交换两者元素,循环以上。

循环最终结果:左指针指向从左往右第一个大于mid的元素,右指针指向从右往左第一个小于mid的元素,且左指针不在右指针左边。

(选择排序做法)继续递归右指针往右部分的数组和右指针往左部分的数组。

(这道题做法)若右指针的位置在k右边,则递归右指针往左部分,否则递归右指针往右部分。

初写时犯了不少错误,也有很多问题:

错误一:最后将mid移至left的位置

一开始的想法是mid既然是中间就要移到中间的位置,然后若mid正好在k的位置就可以直接返回mid,这样做很麻烦并且不一定正确。

错误二:将双指针分别设在首个元素的后一位、最后一个元素

这样做会忽略掉一些元素,这样的话循环就不能先do再while了,可能会陷入死循环,总之比较麻烦。

错误三:最终以左节点作为分割线

大概就是把

cpp 复制代码
if(right>=k) return quicksort(mid,right,k);
        else return quicksort(right+1,r,k);

写成了:

cpp 复制代码
if(left>=k) return quicksort(mid,left-1,k);
        else return quicksort(left,r,k);

其实现在也不是很明白为什么不能以左节点分割,我想可能是因为左指针最开始还要先经过mid,多了一次停留。

总之以后写快排的时候注意这几个地方就好了。

堆排序

堆排序做这题会更简单。

之前不知道堆是什么,现在才知道是一种二叉树,大根堆就是将大的数作为根节点。

cpp 复制代码
class Solution {
public:
    void adjustheap(vector<int>& nums,int root){
        int left=root*2+1;
        int right=root*2+2;
        int maxx=root;
        if(left<nums.size()&&nums[left]>nums[maxx]) maxx=left;
        if(right<nums.size()&&nums[right]>nums[maxx]) maxx=right;
        if(maxx!=root){
            swap(nums[maxx],nums[root]);
            adjustheap(nums,maxx);
        }
    }
    void initheap(vector<int>& nums){
        for(int i=nums.size()/2-1;i>=0;i--){
            adjustheap(nums,i);
        }
    }
    int findKthLargest(vector<int>& nums, int k) {
        initheap(nums);
        for(int i=0;i<k-1;i++){
            nums[0]=-10001;
            adjustheap(nums,0);
        }
        return nums[0];
    }
};

这些函数包括初始化大根堆、调整大根堆的过程。

大根堆就是一个数组,只不过逻辑结构是二叉树,所以不用建树那些过程

初始化大根堆:

从最后一个非叶子节点(nums.size()/2-1)开始调整大根堆。

调整大根堆:

输入root节点,比较root和左右节点,最大的节点若不是root则和root交换,然后递归调整最大那个节点。

这道题不需要进行堆排序,只要构建完大根堆不断删除最顶节点k-1步即可。

相关推荐
椰萝Yerosius2 小时前
[题解]2023CCPC黑龙江省赛 - Ethernet
算法·深度优先
IT猿手2 小时前
基于 Q-learning 的城市场景无人机三维路径规划算法研究,可以自定义地图,提供完整MATLAB代码
深度学习·算法·matlab·无人机·强化学习·qlearning·无人机路径规划
竹下为生4 小时前
LeetCode --- 448 周赛
算法·leetcode·职场和发展
未名编程4 小时前
LeetCode 88. 合并两个有序数组 | Python 最简写法 + 实战注释
python·算法·leetcode
Cuit小唐5 小时前
C++ 迭代器模式详解
c++·算法·迭代器模式
2401_858286115 小时前
CD37.【C++ Dev】string类的模拟实现(上)
开发语言·c++·算法
CQY05315 小时前
蓝桥杯2025年第十六届省赛真题-水质检测
职场和发展·蓝桥杯
╭⌒心岛初晴5 小时前
JAVA练习题(2) 找素数
java·开发语言·算法·java练习题·判断素数/质数
懒懒小徐5 小时前
2023华为od统一考试B卷【二叉树中序遍历】
数据结构·算法·华为od
Star Curry6 小时前
【读书笔记】《编码:隐匿在计算机软硬件背后的语言》01 逻辑与开关
stm32·单片机·嵌入式硬件·职场和发展·51单片机·学习方法