【Leetcode】215. 数组中的第K个最大元素

题目描述

在这里插入图片描述

// 215. 数组中的第K个最大元素

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

题解

// 毫无意义的解(但效果不错)
// 执行用时:2 ms, 在所有 Java 提交中击败了91.08%的用户
// 内存消耗:38.6 MB, 在所有 Java 提交中击败了82.18%的用户
class Solution {
    public int findKthLargest(int[] nums, int k) {
        Arrays.sort(nums);
        return nums[nums.length - k];
    }
}



// 最小堆法
// 傻瓜方法,跟【剑指offer】40. 最小的k个数 有点像,不过还不是很一样。
// 要找最大的k个数,就创建大小为k的最小堆(用优先队列模拟,默认堆顶是最小值)
// ,而且最小堆minHeap中只存储nums中最大的k个数。那么nums中的最大的
// k个数都在minHeap中了,而且minHeap是最小堆,所以堆顶元素就是第k大的数。
// 
// 具体实现:遍历nums所有元素,如果minHeap为空,或者minHeap的长度不足k,则
// 直接将遍历元素num存入minHeap中,如果minHeap长度达到k,则已经定义为装满,
// 之后再遍历到的元素num将和minHeap的堆顶元素对比,如果num大于堆顶元素
// 那将minHeap堆顶元素弹出,将num存入minHeap。如此循环,可以保证,
// 在遍历过nums的所有元素之后,minHeap装的k个元素是nums中最大的k个数,
// 并且堆顶元素就是第k大元素。
// 
// 不清楚的可以打印出堆的情况看看 System.out.println(minHeap); 
// [3,2,1,5,6,4] 和 k = 2

// 执行用时:8 ms, 在所有 Java 提交中击败了37.70%的用户
// 内存消耗:38.5 MB, 在所有 Java 提交中击败了93.01%的用户
class Solution {
    public int findKthLargest(int[] nums, int k) {
		PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
		for (int num: nums) {
            if (minHeap.isEmpty())
                minHeap.add(num);
			else if (minHeap.size() < k)
				minHeap.add(num);
            else if (minHeap.size() >= k && num > minHeap.peek()) {
                minHeap.poll();
                minHeap.add(num);
            }
		}
		return minHeap.peek();
    }
}


// 简化一下
// 执行用时:5 ms, 在所有 Java 提交中击败了54.12%的用户
// 内存消耗:38.7 MB, 在所有 Java 提交中击败了66.71%的用户
import java.util.PriorityQueue;
class Solution {
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();
        for (int num: nums) {
            if (minHeap.size() < k || num > minHeap.peek()) 
                minHeap.add(num);
            while (minHeap.size() > k)
                minHeap.remove(minHeap.peek());
            // System.out.println(minHeap);
        }
        return minHeap.peek();
    }
}
// 快排选择法
// 将nums.length - k赋给kth,我们不需要所有nums元素进行排序,
// 只需要选择nums前nums.length - k个元素进行排序,然后取到nums.length - k
// 即可。将nums.length - k记为kth。直接把快排的partition写进来,swap写进来,
// 重写快排递归函数quickSortSelect,partition求得的mid,再次递归之前进行判定
// ,如果mid和kth相等,则直接将arr[mid]赋值给res,之后结束递归,返回结果res。
// 如果mid小于kth,则mid还需要右移,递归调用,令left为mid+1,
// 如果mid大于等于kth,则说明mid还需要左移,递归调用,令right为mid-1。
// 当mid等于kth时,排序完成,令res等于arr[mid]。直接返回res即可。
// 
// 执行用时:10 ms, 在所有 Java 提交中击败了29.98%的用户
// 内存消耗:38.9 MB, 在所有 Java 提交中击败了29.90%的用户
public class Solution {
	int kth;
    int res = 0;

    public int findKthLargest(int[] nums, int k) {
		this.kth = nums.length - k;
		quickSortSelect(nums, 0, nums.length - 1);
        return res;
	}

    private void quickSortSelect(int[] arr, int left, int right) {
		int mid = partition(arr, left, right);
		if (mid == kth) 
			res = arr[mid];
		else if (mid < kth) 
			quickSortSelect(arr, mid + 1, right);
		else 
            quickSortSelect(arr, left, mid - 1);
		return;
    }

    private static int partition(int[] arr, int left, int right) {
        int pivot = arr[left];
        int l = left;
        int r = right;
        while (l < r) {
            while (l <= r && arr[l] <= pivot)
                l++;
            while (l <= r && arr[r] >= pivot)
                r--;
            if (l < r)
                swap(arr, l, r);
        }
        arr[left] = arr[r];
        arr[r] = pivot;
        return r;
    }

    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}


// 减少递归的修改
// 执行用时:10 ms, 在所有 Java 提交中击败了29.98%的用户
// 内存消耗:38.6 MB, 在所有 Java 提交中击败了78.18%的用户
public class Solution {
	int kth;
    int res = 0;

    public int findKthLargest(int[] nums, int k) {
		this.kth = nums.length - k;
		quickSortSelect(nums, 0, nums.length - 1);
        return res;
	}

    private void quickSortSelect(int[] arr, int left, int right) {
		while (true) {
			int mid = partition(arr, left, right);
			if (mid == kth) {
				res = arr[mid];
				break;
			}
			else if (mid < kth) 
				left = mid + 1;
			else 
				right = mid - 1;
		}
    }

    private static int partition(int[] arr, int left, int right) {
        int pivot = arr[left];
        int l = left;
        int r = right;
        while (l < r) {
            while (l <= r && arr[l] <= pivot)
                l++;
            while (l <= r && arr[r] >= pivot)
                r--;
            if (l < r)
                swap(arr, l, r);
        }
        arr[left] = arr[r];
        arr[r] = pivot;
        return r;
    }

    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

锥栗

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

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

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

打赏作者

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

抵扣说明:

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

余额充值