Kth Largest Element in an Array解题心得

Kth Largest Element in an Array解题心得

https://leetcode.com/problems/kth-largest-element-in-an-array/description/

题目描述

如题意所示:寻找第K大的数,这里选这道题的原因是因为,在查阅这道题更优的算法时,引出了一个重要而且可以在其他题目里使用的算法,即为 Partition 算法,以及一个极其精简版本的partition代码

Partition算法

在解这道题前先描述一种Partition算法:
无序序列 S={a0,a1,a2,a3,....an}
随机取一个数为中间数 pivot=ai
算法的目的是使得序列 S 分成两个个子序列S1,S2,
其中:
S1ai<=pivot
S2ai>pivot
实现方法通过两个头尾指针  left right ,同时向中间过滤,直到碰到冲突的情况即对于左边 S[left]>pivot ,对于右边 S[right]<=pivot ,每次将两个冲突的元素交换;再重复两指针向中间过滤,直到两指针相遇即 left>=right

  • 简单版本代码如下:

    int partition(vector<int> &nums, int begin, int end){
         //[begin, end)
            end--;
            int pivot=nums[begin]
            while(begin<end){
                while(begin<=end&&nums[begin]<=pivot) begin++;
                while(begin<=end&&nums[end]>pivot) end--;
                if (begin<end) {
                    int temp=nums[begin];
                    nums[begin]=nums[end];
                    nums[end]=temp;
                }
            }
            return begin;
       }
  • 在查阅资料的过程中我发现一个更加精妙的一个实现:

    int partition(vector<int> &nums, int begin, int end){
        //[begin, end)
        int pivot=nums[begin];
        while(begin<end){
            while(begin<end&&nums[--end]>pivot);
            nums[begin]=nums[end];
            while(begin<end&&nums[++begin]<=pivot);
            nums[end]=nums[begin];
        }
        nums[begin]=pivot;
        return begin;
    
    }
  • 在这里的代码我们可以看到,这里没有用到交换的过程,而是通过pivot元素实现了全局的左右交换,而且代码的实现精简而又富有对称性

  • 对partition的研究和可以应用到快速排序算法中,甚至还能进一步实现three path partition问题(即将S分为三组,分别为小于,等于,大于)

将partition算法应用于求第k大的数

  • 以分治的思想我们可以逐步将问题分解化

    • 先对序列进行partition算法,分为两部分
    • 大于等于部分的元素个数与k比较
    • 决定第k大的数在哪一部分,再对新的部分重复上述partition算法,缩小求解的范围,最后得到第k大的数
    • 实现
    
    #include <stdio.h>
    
    
    class Solution {
    public:
        int findKthLargest(vector<int>& nums, int k) {
            int begin=0, end=nums.size();
            while(begin<end){
                int pivot=partition(nums, begin, end);
                if (k-1==pivot){
                    return nums[pivot];
                }
                else if (k-1<pivot){
                    end=pivot;
                }
                else {
                    begin=pivot+1;
                }
            }
            return nums[begin];
        }
        int partition(vector<int> &nums, int begin, int end){
            int pivot=nums[begin];
            while(begin<end){
                while(begin<end&&nums[--end]<=pivot);
                nums[begin]=nums[end];
                while(begin<end&&nums[++begin]>=pivot);
                nums[end]=nums[begin];
            }
            nums[begin]=pivot;
            return begin;
        }
    };
  • 算法的时间复杂度可以通过递推式得到: T(n)=T(n/2)+O(n)

  • 则实际复杂度为 O(n)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值