关闭

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

标签: leetcode215. Kth Largest EleJava and C++分治法
297人阅读 评论(0) 收藏 举报
分类:

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);
        }
    }
};




1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:33799次
    • 积分:983
    • 等级:
    • 排名:千里之外
    • 原创:63篇
    • 转载:6篇
    • 译文:0篇
    • 评论:6条
    文章分类
    最新评论