【LeetCode】215. Kth Largest Element in an Array,基于Java和C++的解法

215. Kth Largest Element in an Array

Total Accepted: 57859 Total Submissions: 171725 Difficulty: Medium

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

For example,
Given [3,2,1,5,6,4] and k = 2, return 5.

Note: 
You may assume k is always valid, 1 ≤ k ≤ array's length.

【Section one】分析

题意输入一个未排序的数组,寻找第K大的数并返回。初见之下,这个题似乎比较简单,但实际操作中遇到一些有趣的问题:

      1、采用Java,Accepted的算法,用C++实现出现了内存超限(Memory Limit Exceed);

      2、Java和C++不同的内存管理模式;

分析:

     寻找数组中第K大的数据,一个直观的思路是将数组排序,然后直接通过索引返回第K大的数据。这样做完全可以实现,但是明显做了很多无用功,由于我们只需寻找第K大的数,完全没有必要进行全排序。在所有基本的排序算法中,快速排序是一种比较优秀的算法,平均时间复杂度O(nlogn),在排序中用到的一个重要思想:分治!每一次partition时,返回的都是分割后作为“”的元素的下标,其左边的元素均小于等于它,其右边的元素均大于它,因此,经过分割后,若“”元素在数组中的下标为p,则“”元素为第lengthOfArray-p大的元素;基于这种思想我们可以很快写出两种风格的程序。

【Section two】

基于Java语言的解法一:

class Solution {
    public int findKthLargest(int[] nums, int k) 
    {
    	return quickSort(0,nums.length-1,nums,k);        
    }
    
    int quickSort(int low,int high,int[] temp,int k)
    {
    	if(low>=high)return temp[low];//递归结束的约束条件
    	int point=partition(low,high,temp);//每一次分割后“轴”的下标
    	
    	if(temp.length-point==k) return temp[point];
    	else if(temp.length-point>k){
    		return quickSort(point+1,high,temp,k);
    	}
    	else{
    		return quickSort(low,point-1,temp,k);
    	}
    }
    
    public int partition(int low,int high,int[] temp)//采用分治的思想
    {
    	int cur=temp[low];
    	while(low<high)
    	{
    		while(low<high&&temp[high]>=cur)
    			--high;
    		temp[low]=temp[high];
    		while(low<high&&temp[low]<=cur)
    			++low;
    		temp[high]=temp[low];
    	}
    	temp[low]=cur;
    	return low;
    }
}

基于Java的解法二:

   这个解法与解法一相比,都是“分治”的思想,但是,解法二中却消耗了大量的内存!!!!,随着递归的进行,每一层都需要分配内存用于存储子数组,且此题给定的形参为int[],而根据需要我们定义的是具有动态增删功能的数组列表,在递归调用的时候,还需要复杂的转化,这也会造成时间和空间的消耗。

class Solution2 {
    public int findKthLargest(int[] nums, int k) 
    {
        List<Integer> leftarray=new ArrayList<Integer>();
        List<Integer> rightarray=new ArrayList<Integer>();//定义两个数组列表存储分割后的数组
       
        for(int i=1;i<nums.length;i++)
        {
            if(nums[i]<=nums[0])//以第一个元素为轴,将数组分成两个子数组
            {
            	leftarray.add(nums[i]);//左数组为小于等于转轴的元素
            }
            else
            {
            	rightarray.add(nums[i]);
            }
        }
        
        if(rightarray.size()>=k)//此情况下,第k大的元素必然存在于右子树组
        {
        	int[] rightRemain=new int[rightarray.size()];
        	int i=0;
        	for(Integer e:rightarray)//由于给定的方法的形参列表为int[],这里需要转换一下
        		rightRemain[i++]=e;
        	return findKthLargest(rightRemain, k);
        }
        else if(rightarray.size()==k-1)
        {
        	return nums[0];
        }
        else
        {
        	int[] leftRemain=new int[leftarray.size()];
        	int i=0;
        	for(Integer e:leftarray)
        		leftRemain[i++]=e;
        	return findKthLargest(leftRemain, k-rightarray.size()-1);
        }
       
    }
}

</pre><p></p><pre>

基于C++的解法:

     如下为基于C++的解法,和基于Java的解法二完全相同,看上去程序更为简洁,但是,在LeetCode平台上会出现内存超限(Memory Limit Exceeded)的问题,这与C++中内存的管理模式有关:vector其中一个特点:内存空间只会增长,不会减小,援引C++ Primer:为了支持快速的随机访问,vector容器的元素以连续方式存放,每一个元素都紧挨着前一个元素存储。设想一下,当vector添加一个元素时,为了满足连续存放这个特性,都需要重新分配空间、拷贝元素、撤销旧空间,这样性能难以接受。因此STL实现者在对vector进行内存分配时,其实际分配的容量要比当前所需的空间多一些。就是说,vector容器预留了一些额外的存储区,用于存放新添加的元素,这样就不必为每个新元素重新分配整个容器的内存空间。

    同时,vector的clear()方法只能清除vector中的元素却无法释放其占用内存,一般通过vector<int>().swap(p)来释放。swap()是交换函数,使vector离开其自身的作用域,从而强制释放vector所占的内存空间。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k)
    {
        vector<int> leftArray;
        vector<int> rightArray;
        
        for(int i=1;i<nums.size();i++)
        {
            if(nums[i]<=nums[0])
            leftArray.push_back(nums[i]);
            else
            rightArray.push_back(nums[i]);
        }
        
        if(rightArray.size()>=k)
        {
            vector<int>(leftArray).swap(leftArray);
            return findKthLargest(rightArray, k);
        }
        else if(rightArray.size()==k-1)
        {
            return nums[0];
        }
        else
        {
            int len=k-rightArray.size()-1;
            vector<int>().swap(rightArray);
            return findKthLargest(leftArray, len);
        }
    }
};




  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jin_Kwok

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值