力扣215题,数组中的第K个最大元素

力扣215题,数组中的第K个最大元素

题目描述

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

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

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

输入输出样例

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

解法一,暴力解法

//解法一不考虑时间复杂度
//时间复杂度为O(nlogn)
    int findKthLargest(vector<int>&nums,int k)
    {  
        if(nums.empty())
        {
            return NULL;
        }

        sort(nums.begin(),nums.end());

        int length=nums.size();
        return nums[length-k];
    }

时复 O(NlogN) 空复 O(logN)

解法二,使用快速排序,先排序再取值(三路排序)

//使用快速排序的思想完成

    int findKthLargest2(vector<int>&nums,int k)
    {
        quickSorts2(nums,0,nums.size()-1);

        return nums[nums.size()-k];        
    }

    // void quickSort(vector<int>&nums,int left,int right)
    // {
    //     if(left>=right)
    //     {
    //         return;
    //     }

    //     int pivotIndex=partition(nums,left,right);

    //     quickSort(nums,left,pivotIndex-1);
    //     quickSort(nums,pivotIndex+1,right);
    // }

    //划分在顺序数组和逆序数组上表现很差的
    //解决方法随机选择切分元素

    void randomPartiton(vector<int>&nums,int left,int right)
    {
        int i=left+rand()%(right-left+1);
        swap(nums,i,left);
    }

    void quickSorts2(vector<int>&nums,int left,int right)
    {   
        //当左边大于右边,那么就可以跳出循环
        if(left>=right)
        {
            return;
        }

        randomPartiton(nums,left,right);
        int pivot=nums[left];

        // 将pivot后面的元素划分成三个区间
        //all in nums[left+1,lt)<pivot;
        //all in nums[lt,i)=pivot;
        //all in nums(gt,right]>pivot;

        //设定边界的初始条件
        int lt=left+1;//lt=less than
        int gt=right; //gt= greater than
        int i=left+1;

        while(i<=gt)
        {
            //当元素小于当前划分的值时
            if(nums[i]<pivot)
            {
                //交换到等于pivot区间的第一个位置
                swap(nums,i,lt);
                lt++;
                i++;
            }
            else if(nums[i]==pivot)
            {
                //划分在第二个区间里
                i++;
            }
            else{
                 //划分到数组的末尾
                 swap(nums,i,gt);
                 gt--;   
            }
        }
        //交换 pivot
        swap(nums,left,lt-1);



        //继续递归进行排序
        quickSorts2(nums,left,lt-2);
        quickSorts2(nums,gt+1,right);
    }

    void swap(vector<int>&nums,int index1,int index2)
    {
        int temp=nums[index1];
        nums[index1]=nums[index2];
        nums[index2]=temp;
    }

解法三,借用快速排序进行减治的算法(双端)

void swap(vector<int>&nums,int index1,int index2)
    {
        int temp=nums[index1];
        nums[index1]=nums[index2];
        nums[index2]=temp;
    }


    //借用快速排序的思想,使用减治的方法
    //根据题意第k个元素,即代表要找到pivot恰好等于length-k;

    int findKthLargest3(vector<int>&nums,int k)
    {
        //初始化参数
        int length=nums.size();
        int left=0;
        int right=nums.size()-1;
        int target=length-k;

        //利用双路快排的思想寻找中枢

        while(left<=right)
        {
            int pivotIndex=partitionDouble(nums,left,right);
            if(pivotIndex==target)
            {
                return nums[pivotIndex];
            }
            else if(pivotIndex<target)
            {
                 left=pivotIndex+1;
            }
            else{
                
                right=pivotIndex-1;
            }
        }
    }

     int partitionDouble(vector<int>&nums,int left,int right)
     {
        //随机选取
        randomPartiton(nums,left,right);
        int pivot=nums[left];

        //设定两个区间
        //[left+1,le)<=pivot;
        //(ge,right]>=pivot;

        //初始化两个区间使得原始为空
        int le=left+1;
        int ge=right;

        while(true)
        {
            //le遇到比pivot大的停下来
            while(le<=ge&&nums[le]<pivot)
            {
                le++;
            }

            //ge遇到比pivot小的停息来
            while(le<=ge&&nums[ge]>pivot)
            {
                ge--;
            }

            if(le>=ge)
            {
                break;
            }

            //交换二者的值
            swap(nums,le,ge);
            le++;
            ge--;
        }

        //交换pivot
        swap(nums,left,ge);
        return ge;
     }

时复:O(n)

空复:O(logn)

解法四,借用堆排序的方法(最大堆)

 //使用堆排序的方法
    int findKthLargest4(vector<int>&nums,int k)
    {
        int heapSize=nums.size();
        //建立堆
        buildMaxHeap(nums,heapSize);

        //从最大堆剔除,并逐渐进行重建
        for(int i=nums.size()-1;i>=nums.size()-k+1;i--)
        {
            swap(nums,0,i);
            heapSize--;
            maxHeapiy(nums,0,heapSize);
        }
        return nums[0];
    }

    void buildMaxHeap(vector<int>&nums,int heapSize)
    {
        for(int i=heapSize/2;i>=0;i--)
        {
            maxHeapiy(nums,i,heapSize);   
        }
    }

    void maxHeapiy(vector<int>&nums,int i,int heapSize)
    {
        int left=i*2+1;
        int right=i*2+2;
        int largest=i;

        if(left<heapSize&&nums[left]>nums[largest])
        {
            largest=left;
        }

        if(right<heapSize&&nums[right]>nums[largest])
        {
            largest=right;
        }

        if(largest!=i)
        {
            swap(nums,i,largest);
            maxHeapiy(nums,largest,heapSize);

        }
    }

时复O(nlogn)

空复O(logn)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
请问您需要的是两个数组的交集元素还是交集元素的数量? 如果是交集元素,可以采用双指针的方式,先将两个数组排序,然后设定两个指针 i 和 j,分别指向两个数组的开头,比较两个指针所指向的元素的大小,如果相等,则说明找到了一个交集元素,将其存到结果数组中;如果不相等,则将指向小的元素的指针向后移动一位,直到其中一个指针越界为止。 代码实现如下: ```c int* intersect(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){ int i = 0, j = 0, k = 0; int* res = (int*)malloc(sizeof(int) * (nums1Size > nums2Size ? nums2Size : nums1Size)); // 排序 qsort(nums1, nums1Size, sizeof(int), cmp); qsort(nums2, nums2Size, sizeof(int), cmp); while (i < nums1Size && j < nums2Size) { if (nums1[i] == nums2[j]) { res[k++] = nums1[i]; i++; j++; } else if (nums1[i] < nums2[j]) { i++; } else { j++; } } *returnSize = k; return res; } int cmp(const void* a, const void* b) { return *(int*)a - *(int*)b; } ``` 如果是交集元素的数量,可以采用哈希表的方式,用一个哈希表来记录第一个数组中元素出现的次数,然后遍历第二个数组,在哈希表中查找是否存在相同的元素,如果存在,则说明找到了一个交集元素,将其计数并从哈希表中删除该元素,最后返回计数结果即可。 代码实现如下: ```c int* intersect(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){ int i = 0, j = 0, k = 0; int* res = (int*)malloc(sizeof(int) * (nums1Size > nums2Size ? nums2Size : nums1Size)); int* hash = (int*)malloc(sizeof(int) * 1001); // 由于目条件限制在 [0, 1000] 范围内,所以哈希表可以开得比较小 memset(hash, 0, sizeof(hash)); for (i = 0; i < nums1Size; i++) { hash[nums1[i]]++; } for (j = 0; j < nums2Size; j++) { if (hash[nums2[j]] > 0) { res[k++] = nums2[j]; hash[nums2[j]]--; } } *returnSize = k; return res; } ``` 希望这些代码能够帮到您,如有疑问请随时问我~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值