leetcode-215-数组中的第K个最大元素 (kth largest element in an array)-java

题目及测试

package pid215;
/*数组中的第K个最大元素

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

示例 1:

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

示例 2:

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

说明:

你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。

*/


public class main {
	
	public static void main(String[] args) {
		int[][] testTable = {{1,2,3,2},{1,2,3,4},{1,1,1,3,3,4,3,2,4,2},{3,2,1,5,6,4}};
		for (int[] ito : testTable) {
			test(ito,2);
		}
	}
		 
	private static void test(int[] ito,int k) {
		Solution solution = new Solution();
		int rtn;
		long begin = System.currentTimeMillis();
		for (int i = 0; i < ito.length; i++) {
		    System.out.print(ito[i]+" ");		    
		}
		System.out.println();
		//开始时打印数组
		
		rtn = solution.findKthLargest(ito,k);//执行程序
		long end = System.currentTimeMillis();	
		
		//System.out.println(ito + ": rtn=" + rtn);
		System.out.println(": rtn=" +rtn);
		
		
		System.out.println();
		System.out.println("耗时:" + (end - begin) + "ms");
		System.out.println("-------------------");
	}

}

解法1(成功,4ms,超快)

使用最小堆的方法,求第k大,建立一个规模为k的最小堆

首先将nums前k个元素加入堆,然后初始化最小堆,让heap[0]为这k个元素小的

然后将nums第k到length-1个,依次与heap[0]比较
如果比它大,则替代heap【0】,然后下沉,让heap[0]继续是这k个最小的
所以最后,heap为nums中前k大的,heap[0]为第k大的

该方法速度为o(nlogk),比全部排序o(nlogn)快

package pid215;

import java.util.Arrays;

import javax.naming.InitialContext;

public class Solution {
public int findKthLargest(int[] nums, int k) {
    int length=nums.length;
    int[] heap=new int[k];
    for(int i=0;i<k;i++){
    	heap[i]=nums[i];
    }
    //先建立一个最小堆
    for(int i=k-1;i>=0;i--){
		upAdjust(heap,i,k);
	}
    //将其他的数与最小堆的顶部比较,比它大则替代顶部,然后下沉
    for(int i=k;i<length;i++){
    	int now=nums[i];
    	if(now<=heap[0]){
    		continue;
    	}
    	else{
    		heap[0]=now;
    		downAdjust(heap, 0, k);
    	}
    }	
	return heap[0];
    }

	//调整i位和它的子节点的大小,使小的上浮
	public static void upAdjust(int[] nums,int i,int length){
		int left=2*i+1;
		int right=2*i+2;
		if(left<length&&nums[left]<nums[i]){
			swap(nums, i, left);
		}
		if(right<length&&nums[right]<nums[i]){
			swap(nums, i, right);
		}
		if(left<length){
			upCheck(nums, left, length);
		}
		if(right<length){
			upCheck(nums, right, length);
		}
		
		
	}
	public static void upCheck(int[] nums,int i,int length){
		int left=2*i+1;
		int right=2*i+2;
		if((left<length&&nums[left]<nums[i])||(right<length&&nums[right]<nums[i])){
			upAdjust(nums, i, length);
		}
			
	}
	
	public static void downAdjust(int[] nums,int i,int length){
		int left=2*i+1;
		int right=2*i+2;
		if(left<length&&nums[left]<nums[i]&&(right>=length||(right<length&&nums[left]<=nums[right]))){
			swap(nums, i, left);
			downAdjust(nums, left, length);
		}
		if(right<length&&nums[right]<nums[i]&&nums[left]>nums[right]){
			swap(nums, i, right);
			downAdjust(nums, right, length);
		}
	}
	public static void swap(int[] nums,int i,int j){
		int temp=nums[i];
		nums[i]=nums[j];
		nums[j]=temp;
	}
}

解法2(成功,8ms,较快)

还是用小顶堆

逻辑更清晰了一些

public class Solution {
	// 堆排序,第k大,建立一个k大小的最小堆
	// left为2*index+1,right为2*index+2,parent为(index-1)/2
    public int findKthLargest(int[] nums, int k) {
        int length=nums.length;
        if(length==0||k<=0||k>length){
        	return 0;
        }
        int[] stack=new int[k];
        for(int i=0;i<k;i++){
        	stack[i]=nums[i];
        }
        for(int i=k-1;i>=0;i--){
        	checkNodeAndSwap(stack, i);
        }
        for(int i=k;i<length;i++){
        	if(nums[i]>stack[0]){
        		stack[0]=nums[i];
        		checkNodeAndSwap(stack, 0);
        	}
        }        	    	
    	return stack[0];
    }
    
    // 如果index有孩子,并且孩子比index小,交换二者,保证交换后,index比两个孩子小,如果交换了,保证孩子比孩子的孩子小
    private void checkNodeAndSwap(int[] stack,int index){
    	checkLeftAndSwap(stack, index);
    	checkRightAndSwap(stack, index);
    }
    
    // 如果index有左孩子,并且左孩子比index小,交换二者,如果交换了,保证左孩子比左孩子的孩子小
    private void checkLeftAndSwap(int[] stack,int index){
    	// 先保证自己有,左孩子有
    	int leftIndex=2*index+1;
    	if(index>=stack.length||leftIndex>=stack.length){
    		return;
    	}
    	if(stack[leftIndex]<stack[index]){
    		swap(stack, index, leftIndex);
    		checkNodeAndSwap(stack, leftIndex);
    	}
    }
    
    private void checkRightAndSwap(int[] stack,int index){
    	int rightIndex=2*index+2;
    	if(index>=stack.length||rightIndex>=stack.length){
    		return;
    	}
    	if(stack[rightIndex]<stack[index]){
    		swap(stack, index, rightIndex);
    		checkNodeAndSwap(stack, rightIndex);
    	}
    }
    
    private void swap(int[] stack,int i,int j){
    	int temp=stack[i];
    	stack[i]=stack[j];
    	stack[j]=temp;
    }
}

解法3(别人的)

利用快速排序的思想,在进行排序过程中每次可以确定一个元素的最终位置,若此位置为第K个最大元素,则直接返回此索引,否则继续分治进行快速排序。不用排列全部,只要每次只排序一段,找到即可

class Solution {
    public int findKthLargest(int[] nums, int k) {
        int begin=0;
        int end=nums.length-1;
         k=nums.length+1-k;
         while(begin<end){
            int pos=partition(nums,begin,end);
            if(pos==k-1) break;
            else if(pos<k-1) begin=pos+1;
            else end=pos-1;
        }
        return nums[k-1];
    }
    public int partition(int[]nums,int l,int r){
          int less=l-1;//小于区的下标
          int  more=r;//大于区的下标,默认以最后一个下标的数作为划分值
          while(l<more){
              if(nums[l]<nums[r])
                 swap(nums,++less,l++);
              else if  (nums[l]>nums[r]) 
                 swap(nums,--more,l);
              else l++;
          }
          swap(nums,more,r);
          return less+1;//小于区位置+1可以得到划分的这个数的下标
      }
    private void swap(int[] a, int i, int j) {
          int t = a[i];
          a[i] = a[j];
          a[j] = t;
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值