Open azl397985856 opened 2 years ago
可以直接sort, 也可以用堆排序来做。 这里我们使用堆排序来实现。
根据test case的测试发现 1 <= k <= nums.length, 即k总是处于合法范围, 不会超过nums数组的长度。
先把nums数组中的元素都放进大顶堆, 然后弹出k-1个数, 此时再取优先队列的top值即为所求。
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
int res;
priority_queue<int> q;
for (auto& num : nums)
q.push(num);
while (!q.empty() && k > 1)
{
auto top = q.top();
q.pop();
k--;
}
res = q.top();
return res;
}
};
Heap. If heap.length < k, push current element into heap. If heap.length >= k and current element is larger than heap's first element, push current element into heap and pop out heap's first element.
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
heap = []
for i in nums:
if len(heap) < k:
heapq.heappush(heap, i)
else:
if i > heap[0]:
heapq.heappush(heap, i)
heapq.heappop(heap)
return heap[0]
Time: O(N log K). Build heap is O(K log K). Heappop and heappush is O(log K). Space: O(K)
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
if not nums or k < 1 or k > len(nums):
return -1
return self.quick_select(nums, 0, len(nums) - 1, k)
def quick_select(self, nums, start, end, k):
if start == end:
return nums[start]
i, j = start, end
pivot = nums[(i + j) // 2]
while i <= j:
while i <= j and nums[i] > pivot:
i += 1
while i <= j and nums[j] < pivot:
j -= 1
if i <= j:
nums[i], nums[j] = nums[j], nums[i]
i += 1
j -= 1
# start, j, i, end
if k <= j - start + 1:
return self.quick_select(nums, start, j, k)
if k >= i + 1 - start:
# i - start is the total number of elements before index i
return self.quick_select(nums, i, end, (k - (i - start)))
return nums[j + 1]
思路: 方法一、排序 方法二、小顶堆
复杂度分析: 方法一、 时间复杂度: O(nlogn),其中n是数组nums的长度 空间复杂度: O(logn)
方法二、 时间复杂度: O(n + klogk),其中n是数组nums的长度 空间复杂度: O(logk)
代码(C++):
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
int n = nums.size();
priority_queue<int, vector<int>, greater<int>> pq;
int len = 0;
for (auto num : nums) {
if (len < k) {
pq.push(num);
} else if (pq.top() < num) {
pq.pop();
pq.push(num);
}
len++;
}
return pq.top();
}
};
C++ Code:
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
/// two method. One use min heap
priority_queue<int, vector<int>, greater<int>> pq;
for(int i=0; i< nums.size(); i++)
{
if(pq.size()<k)
{
pq.push(nums[i]);
}
else
{
if(nums[i]> pq.top())
{
pq.pop();
pq.push(nums[i]);
}
}
}
return pq.top();
}
};
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
/// two method. One use min heap
int start =0;
int end = nums.size()-1;
k--;
for(int i=0; i< nums.size(); i++)
{
// random choose pivot.
// This part code is very important. It will improve running time from 40ms to 4ms.
int pivotIndex = rand()%(end - start+1)+ start;
swap(nums[start], nums[pivotIndex]);
//
int index = quickSort(nums, start, end);
if(index == k)
return nums[index];
else if(index < k)
{
start = index+1;
}
else
{
end = index - 1;
}
}
return INT_MIN; // assert(0);
}
int quickSort(vector<int>& nums, int start, int end)
{
int pivot = nums[start];
while(start< end)
{
while(start<end && nums[end]<=pivot)
{
end--;
}
swap(nums[start], nums[end]);
while(start<end && nums[start]>pivot)
{
start++;
}
swap(nums[start], nums[end]);
}
nums[start] = pivot;
return start;
}
};
复杂度分析
Java Code:
class Solution {
//使用大堆去做。
//堆的属性:
//底层使用数组实现,数组的索引0处留空,这样就满足了性质1:
//性质1:索引k的节点的子节点索引,2k,2k+1,第k个节点的父亲节点:k/2
//注意点:!!!!!!!!!千万分清索引和索引元素,要不十分容易错
public int findKthLargest(int[] nums, int k) {
//思路很简单,构建一个大堆,然后依次删除堆顶的数(底层操作是数组)
//构建堆时,思路是从len/2处从右往左扫描,并对每个扫描到的元素下沉操作
int len=nums.length;
int[] arr=new int[len+1];
for(int i=1;i<len+1;i++){
arr[i]=nums[i-1];
}
//构建堆
buildHeap(arr);
//删除操作,思路:将堆顶与最后一个元素交换位置,然后忽略掉最后一个元素
int last=arr.length-1;
//堆排序
while(last!=1){
swap(arr,1,last);
last--;
sink(arr,1,last);
}
return arr[arr.length-k];
}
//构建堆
public void buildHeap(int[] nums){
int len=nums.length;
for(int i=(len-1)/2;i>=1;i--){
sink(nums,i,len-1);
}
}
//节点tar下沉操作,步骤:找到左右子节点的大节点(右节点可能不存在),与顶点比较
public void sink(int[] nums,int k,int range){
//最大索引位置,是可以变化的
while(k*2<=range){//判定是不是超过最大值(很巧妙)
int lft=2*k;
int rgt=2*k+1;
//找到左右子节点的大节点索引
int max=lft;
if(rgt<=range){
//右节点存在
if(nums[rgt]>nums[lft]){
max=rgt;
}
}
if(nums[max]>nums[k]){
swap(nums,max,k);
}
k=max;//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!精髓,实则循环替换了递归
}
}
public void swap(int[] nums,int i,int j){
int tmp=nums[i];
nums[i]=nums[j];
nums[j]=tmp;
}
}
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
size = len(nums)
nums.sort()
return nums[size - k]
堆排序。 排成大顶堆,数组变成从小到大的顺序。 取nums[-k] 就是第k大元素
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
# i: parent.
def beHeap(nums, i, length):
# child
k = 2 * i + 1
while k <= length:
if k + 1 <= length and nums[k + 1] > nums[k]:
k = k + 1
if nums[k] > nums[i]: # chile node larger than parent node.
nums[k], nums[i] = nums[i] ,nums[k]
i = k
k = 2 * i + 1
else:
break
# first i should be the last parent = len(nums)/2 - 1
n = int(len(nums) / 2 - 1)
# print(n)
# form a heap
for i in range(n, -1, -1): # 从下到上找。
beHeap(nums, i, len(nums) - 1)
# print(nums)
# take the top to the end of the array. keep form a heap.
for i in range(len(nums) - 1, -1, -1):
nums[0], nums[i] = nums[i], nums[0]
beHeap(nums, 0, i - 1)
return nums[-k]
时间复杂度:O(nlogn),建堆的时间代价是 O(n),删除的总代价是 O(klogn)??,因为 k < n,故渐进时间复杂为 O(n + k log n) = O(nlogn)。 空间复杂度:O(\log n)O(logn),即递归使用栈空间的空间代价
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
heap = []
for n in nums:
if len(heap) < k:
heapq.heappush(heap, n)
elif n > heap[0]:
heapq.heapreplace(heap, n)
return heap[0]
Time complexity: O(NlogK)
Space complexity: O(K)
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> queue = new PriorityQueue<>();
for (int i = 0; i < nums.length; i++) {
queue.add(nums[i]);
if (queue.size() > k) {
queue.poll();
}
}
return queue.peek();
}
public class KthLargestNumber {
public int findKthLargest(int[] nums, int k) {
int n = nums.length;
int targetIndex = n - k;
int start = 0, end = n - 1;
while (true) {
int index = partition(nums, start, end);
if (index == targetIndex) {
return nums[targetIndex];
} else if (index > targetIndex) {
end = index - 1;
} else {
start = index + 1;
}
}
}
private int partition(int[] nums, int start, int end) {
int pivot = start, l = start + 1, r = end;
while (l <= r) {
if (nums[l] > nums[pivot] && nums[r] < nums[pivot]) {
swap(nums, l, r);
l++;
r--;
}
if (nums[l] <= nums[pivot]) {
l++;
}
if (nums[r] >= nums[pivot]) {
r--;
}
}
swap(nums, pivot, r);
return r;
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
priority queue
使用语言:Python 3
import heapq
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
nums_size = len(nums)
h = []
for i in range(k):
heapq.heappush(h, nums[i])
for k in range(k, nums_size):
if nums[k] > h[0]:
heapq.heapreplace(h, nums[k])
return h[0]
复杂度分析 时间复杂度:O(Nlogk) 空间复杂度:O(k)
排序。
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
sort(nums.rbegin(), nums.rend());
return nums[k - 1];
}
};
class Solution {
public int findKthLargest(int[] nums, int k) {
int heapSize = nums.length;
buildMaxHeap(nums, heapSize);
for (int i = nums.length - 1; i >= nums.length - k + 1; --i) {
swap(nums, 0, i);
--heapSize;
maxHeapify(nums, 0, heapSize);
}
return nums[0];
}
public void buildMaxHeap(int[] a, int heapSize) {
for (int i = heapSize / 2; i >= 0; --i) {
maxHeapify(a, i, heapSize);
}
}
public void maxHeapify(int[] a, int i, int heapSize) {
int l = i * 2 + 1, r = i * 2 + 2, largest = i;
if (l < heapSize && a[l] > a[largest]) {
largest = l;
}
if (r < heapSize && a[r] > a[largest]) {
largest = r;
}
if (largest != i) {
swap(a, i, largest);
maxHeapify(a, largest, heapSize);
}
}
public void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
时间复杂度:O(NLogN) 空间复杂度:O(logN)
Go的堆排序,关键是要注意type Iheap 而不能用 type heap!!!
type Iheap []int
func(h Iheap)Len()int{return len(h)}
func(h Iheap)Less(i,j int) bool{return h[i]>h[j]}
func(h Iheap)Swap(i,j int) {h[i],h[j] = h[j],h[i]}
func(h *Iheap) Push(x interface{}) {
*h = append(*h,x.(int))
}
func(h *Iheap) Pop() interface{}{
x := *h
out := x[len(x)-1]
*h = x[:len(x)-1]
return out
}
func findKthLargest(nums []int, k int) int {
if len(nums) < k{
return 0
}
h := &Iheap{}
for i:=0;i<len(nums);i++{
heap.Push(h,nums[i])
}
out:=0
for i:=0;i<k;i++{
out = heap.Pop(h).(int)
}
return out
}
时间复杂度O(NlogK) 空间复杂度O(N)
class Solution { Random random = new Random();
public int findKthLargest(int[] nums, int k) {
return quickSelect(nums, 0, nums.length - 1, nums.length - k);
}
public int quickSelect(int[] a, int l, int r, int index) {
int q = randomPartition(a, l, r);
if (q == index) {
return a[q];
} else {
return q < index ? quickSelect(a, q + 1, r, index) : quickSelect(a, l, q - 1, index);
}
}
public int randomPartition(int[] a, int l, int r) { int i = random.nextInt(r - l + 1) + l; swap(a, i, r); return partition(a, l, r); }
public int partition(int[] a, int l, int r) {
int x = a[r], i = l - 1;
for (int j = l; j < r; ++j) {
if (a[j] <= x) {
swap(a, ++i, j);
}
}
swap(a, i + 1, r);
return i + 1;
}
public void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
var findKthLargest = function(nums, k) {
return nums.sort((a, b) => b - a)[k - 1]
};
冒泡排序
func findKthLargest(nums []int, k int) int {
for i:=0;i<k;i++{
j:=0
for j<len(nums)-1{
if nums[j] <= nums[j+1]{
j++
}else {
nums[j], nums[j+1] = nums[j+1],nums[j]
j++
}
}
}
return nums[len(nums)-k]
}
时间:O(nk) 空间:O(1)
class Solution {
public int findKthLargest(int[] nums, int k) {
int len = nums.length;
if(len == 0) return -1;
Arrays.sort(nums);
return nums[len - k];
}
}
var findKthLargest = function (nums, k) {
let len = nums.length;
let sort = function (nums, k, start = 0, end = nums.length - 1) {
if (start < end) {
let povite = nums[end];
let pos = start - 1;
for (let i = start; i <= end; i++) {
if (nums[i] <= povite) {
pos++;
[nums[pos], nums[i]] = [nums[i], nums[pos]];
}
}
let lastIdx = len - pos;
if (lastIdx === k) {
return nums[pos];
} else if (lastIdx > k) {
return sort(nums, k, pos + 1, end);
} else {
return sort(nums, k, start, pos - 1);
}
}
return nums[len - k];
};
return sort(nums, k);
};
使用构建堆来完成的(topk的问题,可以使用快速选择或者堆来完成)
class Solution { //使用堆排序(在java中可以使用优先队列来完成!!) //建立 大根堆 或者 小根堆 来完成!!! public int findKthLargest(int[] arr, int k) { return fun(arr,k); } private int fun(int[]arr,int k){ // 1.构建小根堆 for(int i=arr.length/2 -1;i>=0;i--){ //从第一个非叶子结点从下至上,从右至左调整结构 adujust(arr,i,arr.length); } //调整堆结构 交换对顶元素 与 末尾元素 for(int j=arr.length-1;j>0;j--){ swap(arr,0,j); adujust(arr,0,j); } return arr[k-1]; } private void adujust(int[] arr,int i,int length){ int temp =arr[i]; for(int k=i*2 +1;k<length;k=2*k+1){ if(k+1<length&&arr[k]>arr[k+1]){ k++; } if(arr[k]<temp){ arr[i] = arr[k]; i = k; }else { break; } } arr[i] = temp; } private void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } }
时间复杂度:O(nlogn)
空间复杂度:O(1)
堆。建立小顶堆储存k个元素。遍历数组,前k个元素放入堆中,从第k+1个元素开始,比较当前元素和堆顶元素。如果当前元素小于等于堆顶元素,当前元素不可能是第k大元素,跳过当前元素;如果当前元素大于堆顶元素,则从堆顶取出最小元素,将当前元素放入堆中。每一时刻堆中储存的都是到当前元素为止前k大的元素。当整个数组遍历结束,堆中保留的便是所有元素中前k大的元素。返回堆顶元素即为结果。
class Solution {
public int findKthLargest(int[] nums, int k) {
// use a min-heap to store k elements
PriorityQueue<Integer> heap = new PriorityQueue<>();
for (int i = 0; i < nums.length; i++) {
if (i < k) {
heap.offer(nums[i]);
continue;
}
// starting from the element with index k, we will check the element with the element from the top of the heap
int top = heap.peek();
// if the element is greater than the top of heap, we will poll the minimum from the heap and add this element in. if the element is no greater than the top, just ignore this element, it could not be the kth largest element
if (nums[i] > top) {
heap.poll();
heap.offer(nums[i]);
}
}
// return the top of the heap, which is the kth largest element
return heap.poll();
}
}
复杂度分析
固定堆
class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> heap = new PriorityQueue<>(k+1);
int c = 0;
for(int num : nums){
heap.offer(num);
c++;
if(c==k+1){
heap.poll();
c=k;
}
}
return heap.peek();
}
}
class MinHeap {
constructor() {
this.heap = [];
}
// 交换节点位置
swap(i1, i2) {
[this.heap[i1], this.heap[i2]] = [this.heap[i2], this.heap[i1]];
}
// 获得父节点
getParentIndex(i) {
return (i - 1) >> 1;
}
// 获得左节点
getleftIndex(i) {
return 2 * i + 1;
}
// 获得右节点
getrightIndex(i) {
return 2 * i + 2;
}
// 上移
shiftUp(index) {
if (index === 0) return;
const parentIndex = this.getParentIndex(index);
if (this.heap[parentIndex] > this.heap[index]) {
this.swap(parentIndex, index);
this.shiftUp(parentIndex);
}
}
// 下移
shiftDown(index) {
const leftIndex = this.getleftIndex(index);
const rightIndex = this.getrightIndex(index);
if (this.heap[leftIndex] < this.heap[index]) {
this.swap(leftIndex, index);
this.shiftDown(leftIndex);
}
if (this.heap[rightIndex] < this.heap[index]) {
this.swap(rightIndex, index);
this.shiftDown(rightIndex);
}
}
// 插入
insert(value) {
this.heap.push(value);
this.shiftUp(this.heap.length - 1);
}
// 删除堆顶
pop() {
// pop()方法删除数组最后一个元素并返回,赋值给堆顶
this.heap[0] = this.heap.pop();
// 对堆顶重新排序
this.shiftDown(0);
}
// 获取堆顶
peek() {
return this.heap[0];
}
// 获取堆的大小
size() {
return this.heap.length;
}
}
const findKthLargest = (nums, k) => {
const minHeap = new MinHeap();
for (const num of nums) {
// 将数组元素依次插入堆中
minHeap.insert(num);
// 如果堆大小超过k, 开始裁员, 将堆顶(最小) 的去掉
if (minHeap.size() > k) minHeap.pop();
}
// 返回堆顶,此时就是第k大的元素
return minHeap.peek();
};
heap
import heapq
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
"""
use heap
"""
heap = []
for num in nums:
if len(heap) < k:
heapq.heappush(heap, num)
elif num > heap[0]:
heapq.heappop(heap)
heapq.heappush(heap, num)
return heap[0]
Time O(nlgk)
Space O(k)
class Solution {
public int findKthLargest(int[] nums, int k) {
int[] sortNums = sortInt(nums);
return sortNums[sortNums.length - k];
}
public int[] sortInt(int []ints){
for(int i = 0;i < ints.length-1;i++){
for(int j = 0;j < ints.length-1-i;j++){
if(ints[j] > ints[j+1]){
int a = ints[j];
ints[j] = ints[j+1];
ints[j+1] = a;
}
}
}
return ints;
}
}
https://leetcode.com/problems/kth-largest-element-in-an-array/
class Solution {
public int findKthLargest(int[] nums, int k) {
if(nums == null || nums.length == 0){
return -1;
}
int n = nums.length;
if(n < k){
return -1;
}
PriorityQueue<Integer> q = new PriorityQueue<>();
for(int i = 0; i < n; i++){
if(q.size() == k){
if(nums[i] > q.peek()){
q.poll();
q.offer(nums[i]);
}
}else{
q.offer(nums[i]);
}
}
return q.peek();
}
}
快排
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
def qselect(nums,left,right):
if left>right:
return nums
l=left
r=right
target=nums[left]
while left<right:
while left<right and nums[right]>=target:
right-=1
nums[left]=nums[right]
while left<right and nums[left]<=target:
left+=1
nums[right]=nums[left]
nums[left]=target
if left==len(nums)-k:
return nums[left]
elif left>len(nums)-k:
return qselect(nums,l,left-1)
else:
return qselect(nums,left+1,r)
return nums
return qselect(nums,0,len(nums)-1)
https://leetcode-cn.com/problems/kth-largest-element-in-an-array/
Heap, quickSelection
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
# time nlogk
# space logn
heap = []
for num in nums:
heapq.heappush(heap, -num)
for _ in range(k):
tmp = heapq.heappop(heap)
return -tmp
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
# time nlogk
# space logn
# 维护一个大小为k的最小堆,堆顶是这k个数里的最小的,遍历完数组后返回堆顶元素即可
heap = []
for num in nums:
heapq.heappush(heap, num)
if len(heap) > k:
heapq.heappop(heap)
return heap[0]
# [1, 2, 3, 4, 5 ,6], k = 2
# [5, 6]
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
def partition(low, high):
# conercase:
# [1,2,3,4,5,6]
# [6,5,4,3,2,1]
pivot = random.randint(low, high)
nums[pivot], nums[low] = nums[low], nums[pivot]
i, j = low, low + 1
while j <= high:
if nums[j] > nums[low]:
nums[i + 1], nums[j] = nums[j], nums[i + 1]
i += 1
j += 1
nums[low], nums[i] = nums[i], nums[low]
return i
def quickSort(low, high):
while True:
# [ ] idx==k-1 [ ]
# 6 5 4 3 2 1
# 0 1 2 3 4 5
# 2thLargest:idx=2-1=1
idx = partition(low, high)
if idx == k - 1:
return nums[idx]
elif idx < k - 1:
# return partition(idx + 1, high)
low = idx + 1
elif idx > k - 1:
# return partition(low, idx - 1)
high = idx - 1
return quickSort(0, len(nums) - 1)
# return nums
维护一个有 k 个元素的最小堆, 最后就是包含 list 中最大的 k 个元素
如果当前堆不满, 直接添加
如果堆满了, 那么这 k 个元素的最小元素在堆顶, 用堆顶元素跟 新的元素 n 做对比, 如果 堆顶元素比 n 小, 那么 pop 堆顶的元素, 并将新的元素 n 加入堆中
最后返回 h[0] 就是 第 k 大的元素 因为堆中 是最大的 k 个元素, 堆顶是 其中最小的元素即第 k 大元素
import heapq
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
# maintain min heap h, everytime find element bigger than heap top element
# heappop the heap top element and push the new element in
h = []
for i, n in enumerate(nums):
if len(h) < k:
heapq.heappush(h, n)
else:
if n > h[0]:
heapq.heappop(h)
heapq.heappush(h, n)
return h[0]
时间复杂度: O(nlogn) 建堆时间代价是 O(n), 删除总代价是 O(klogn), 因为 k < n, 渐进时间复杂度为 O(n+klogn) = O(nlogn)
空间复杂度: O(k) 堆的空间复杂度
Go Code:
type minPriorityQueue []int
func (pq minPriorityQueue) Len() int { return len(pq) }
func (pq minPriorityQueue) Less(i, j int) bool { return pq[i] < pq[j] }
func (pq minPriorityQueue) Swap(i, j int) { pq[i], pq[j] = pq[j], pq[i] }
func (pq *minPriorityQueue) Push(x interface{}) { *pq = append(*pq, x.(int)) }
func (pq *minPriorityQueue) Pop() interface{} {
res := (*pq)[len(*pq)-1]
*pq = (*pq)[:len(*pq)-1]
return res
}
func findKthLargest(nums []int, k int) int {
small := make(minPriorityQueue, 0)
heap.Init(&small)
for _, num := range nums {
heap.Push(&small, num)
if small.Len() > k {
heap.Pop(&small)
}
}
return heap.Pop(&small).(int)
}
复杂度分析
令 n 为数组长度。
import heapq as h
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
heap = []
for num in nums:
# 如果堆长度没到k,无脑塞
if len(heap) < k:
h.heappush(heap, num)
else:
# 如果长度到k了,且当前元素比堆顶要大,我们才加进去,当然要先把最小的pop出来再加!
if num > heap[0]:
h.heappop(heap)
h.heappush(heap, num)
return h.heappop(heap)
Quick Select Solution
class Solution {
public int findKthLargest(int[] nums, int k) {
if(nums == null || nums.length == 0) return 0;
int left = 0;
int right = nums.length - 1;
while(true) {
int pos = partition(nums, left, right);
if(pos + 1 == k) {
return nums[pos];
} else if(pos + 1 > k) {
right = pos - 1;
} else {
left = pos + 1;
}
}
}
private int partition(int[] nums, int left, int right) {
int pivot = nums[left];
int l = left + 1;
int r = right;
while(l <= r) {
if(nums[l] < pivot && nums[r] > pivot) {
swap(nums, l++, r--);
}
if(nums[l] >= pivot) l++;
if(nums[r] <= pivot) r--;
}
swap(nums, left, r);
return r;
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
O(n)
O(1)
PQ Solution
class Solution {
public int findKthLargest(int[] nums, int k) {
if(nums == null || nums.length == 0) return 0;
PriorityQueue<Integer> pq = new PriorityQueue<>();
for(int num : nums) {
pq.offer(num);
if(pq.size() > k) {
pq.poll();
}
}
return pq.poll();
}
}
O(nlogk)
O(n)
堆排序
class Solution {
public int findKthLargest(int[] nums, int k) {
int heapSize = nums.length;
buildMaxHeap(nums, heapSize);
for (int i = nums.length - 1; i >= nums.length - k + 1; --i) {
swap(nums, 0, i);
--heapSize;
maxHeapify(nums, 0, heapSize);
}
return nums[0];
}
public void buildMaxHeap(int[] a, int heapSize) {
for (int i = heapSize / 2; i >= 0; --i) {
maxHeapify(a, i, heapSize);
}
}
public void maxHeapify(int[] a, int i, int heapSize) {
int l = i * 2 + 1, r = i * 2 + 2, largest = i;
if (l < heapSize && a[l] > a[largest]) {
largest = l;
}
if (r < heapSize && a[r] > a[largest]) {
largest = r;
}
if (largest != i) {
swap(a, i, largest);
maxHeapify(a, largest, heapSize);
}
}
public void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
import heapq
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
m = len(nums)
h=[]
for i in range(k):
heapq.heappush(h, nums[i])
for i in range(k, m):
if nums[i] > h[0]:
heapq.heapreplace(h, nums[i])
return h[0]
/*
quick select
*/
class Solution {
public int findKthLargest(int[] nums, int k) {
int left = 0;
int right = nums.length - 1;
while (true) {
int pos = partition(nums,left, right);
if (pos + 1 == k) {
return nums[pos];
} else if (pos + 1 > k) {
right = pos - 1;
} else {
left = pos + 1;
}
}
}
public int partition(int[] nums, int left, int right) {
int pivot = nums[left];
int l = left + 1;
int r = right;
while (l <= r) {
if (nums[l] < pivot && nums[r] > pivot) {
swap(nums, l++, r--);
}
if (nums[l] >= pivot) l++;
if(nums[r] <= pivot) r--;
}
swap(nums, left, r);
return r;
}
public void swap (int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
class Solution {
public int findKthLargest(int[] nums, int k) {
if (nums == null || nums.length == 0) {
return 0;
}
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
for (int num : nums) {
minHeap.offer(num);
if (minHeap.size() > k) {
minHeap.poll();
}
}
return minHeap.poll();
}
}
// S: O(k) (PriorityQueue的size是k
// O(nlgk) 局部排序
// Array.sort: O(nlgn)
// PriorityQueue: O(nlgk)
维护一个size = k的小顶堆,把数字放在里面,如果size > k,那么堆顶的数字出堆。遍历到最后,堆顶的数字就是第k大的。
class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> heap = new PriorityQueue<>();
for (int num: nums) {
heap.offer(num);
if (heap.size() > k) {
heap.poll();
}
}
return heap.peek();
}
}
TC: O(nlogk) SC: O(k)
#直接排序法
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
nums.sort(reverse=True)
return(nums[k-1])
#堆
"""
维护一个大小为K的小顶堆,堆顶是最小元素,当堆的size > K 的时候,删除堆顶元素. 扫描一遍数组,最后堆顶就是第K大的元素。 直接返回。
"""
import heapq
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
size = len(nums)
h = []
for i in range(k):
heapq.heappush(h, nums[i])
for j in range(k,size):
if nums[j] >h[0]:
heapq.heapreplace(h, nums[j])
return h[0]
时间复杂度O(nlogk) 空间复杂度度O(n)
class Solution {
public int findKthLargest(int[] nums, int k) {
//corner case
if (nums.length < k) return 0;
//build a min-heap in a k size
PriorityQueue<Integer> pq = new PriorityQueue<>(k);
for (int i = 0; i < k; i ++) {
pq.offer(nums[i]);
}
for (int i = k; i < nums.length; i ++) {
if (nums[i] > pq.peek()) {
pq.poll();
pq.offer(nums[i]);
}
}
return pq.peek();
}
}
https://leetcode.com/problems/kth-largest-element-in-an-array/
-Heap
Heap
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
heap = nums[:k]
heapq.heapify(heap)
for e in nums[k:]:
if e > heap[0]:
heapq.heappop(heap)
heapq.heappush(heap, e)
return heap[0]
时间复杂度: O(N*Log(K)) 空间复杂度: O(K)
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
hq = []
for i in range(k):
heapq.heappush(hq, nums[i])
for i in range(k, len(nums)):
if nums[i] > hq[0]:
heapq.heappop(hq)
heapq.heappush(hq, nums[i])
return hq[0]
Space: O(k) Time: O(nlogk)
Heap
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
heap = nums[:k]
heapq.heapify(heap)
for num in nums[k:]:
if num > heap[0]:
heapq.heappop(heap)
heapq.heappush(heap, num)
return heap[0]
时间:O(nlogk) 空间:O(k)
import heapq
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
heap = []
# 维护一个长度为k的小顶堆,那么这个堆有k个数比它大,最后取堆顶即可
# 先初始化一个大小为k的小顶堆,依次入堆
for i in range(k):
heapq.heappush(heap, nums[i])
for i in range(k, len(nums)):
# 弹出最小的元素被新的元素替代
if nums[i] > heap[0]:
heapq.heapreplace(heap, nums[i])
return heap[0]
class Solution: def findKthLargest(self, nums: List[int], k: int) -> int: if not nums or k < 1 or k > len(nums): return -1
return self.quick_select(nums, 0, len(nums) - 1, k)
def quick_select(self, nums, start, end, k):
if start == end:
return nums[start]
i, j = start, end
pivot = nums[(i + j) // 2]
while i <= j:
while i <= j and nums[i] > pivot:
i += 1
while i <= j and nums[j] < pivot:
j -= 1
if i <= j:
nums[i], nums[j] = nums[j], nums[i]
i += 1
j -= 1
# start, j, i, end
if k <= j - start + 1:
return self.quick_select(nums, start, j, k)
if k >= i + 1 - start:
# i - start is the total number of elements before index i
return self.quick_select(nums, i, end, (k - (i - start)))
return nums[j + 1]
var findKthLargest = function(nums, k) {
return quickSelect(nums, 0, nums.length - 1, nums.length - k)
}
const quickSelect = (nums, l, r, index) => {
const pos = partition(nums, l, r)
if (pos === index) {
return nums[pos]
} else {
return pos > index ? quickSelect(nums, l, pos - 1, index) : quickSelect(nums, pos + 1, r, index)
}
}
const partition = (nums, l, r) => {
const pivot = nums[r]
let index = l
for (let i = l; i < r; i++) {
if (nums[i] < pivot) {
i !== index && swap(nums, i, index)
index++
}
}
swap(nums, index, r)
return index
}
const swap = (nums, i, j) => {
const temp = nums[i]
nums[i] = nums[j]
nums[j] = temp
}
时间:O(n) 空间:O(logn)
class Solution {
int [] nums;
public void swap(int a, int b) {
int tmp = this.nums[a];
this.nums[a] = this.nums[b];
this.nums[b] = tmp;
}
public int partition(int left, int right, int pivot_index) {
int pivot = this.nums[pivot_index];
// 1. move pivot to end
swap(pivot_index, right);
int store_index = left;
// 2. move all smaller elements to the left
for (int i = left; i <= right; i++) {
if (this.nums[i] < pivot) {
swap(store_index, i);
store_index++;
}
}
// 3. move pivot to its final place
swap(store_index, right);
return store_index;
}
public int quickselect(int left, int right, int k_smallest) {
/*
Returns the k-th smallest element of list within left..right.
*/
if (left == right) // If the list contains only one element,
return this.nums[left]; // return that element
// select a random pivot_index
Random random_num = new Random();
int pivot_index = left + random_num.nextInt(right - left);
pivot_index = partition(left, right, pivot_index);
// the pivot is on (N - k)th smallest position
if (k_smallest == pivot_index)
return this.nums[k_smallest];
// go left side
else if (k_smallest < pivot_index)
return quickselect(left, pivot_index - 1, k_smallest);
// go right side
return quickselect(pivot_index + 1, right, k_smallest);
}
public int findKthLargest(int[] nums, int k) {
this.nums = nums;
int size = nums.length;
// kth largest is (N - k)th smallest
return quickselect(0, size - 1, size - k);
}
}
import heapq
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
heap = []
# 维护一个长度为k的小顶堆,那么这个堆有k个数比它大,最后取堆顶即可
# 先初始化一个大小为k的小顶堆,依次入堆
for i in range(k):
heapq.heappush(heap, nums[i])
for i in range(k, len(nums)):
# 弹出最小的元素被新的元素替代
if nums[i] > heap[0]:
heapq.heapreplace(heap, nums[i])
return heap[0]
【Day 85】215. 数组中的第 K 个最大元素
https://leetcode-cn.com/problems/kth-largest-element-in-an-array/
小顶堆
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
if not nums or k<1 or k>len(nums):
return -1
heap = []
for i in range(k):
heapq.heappush(heap,nums[i])
for i in range(k,len(nums)):
if nums[i]>heap[0]:
heapq.heapreplace(heap,nums[i])
return heap[0]
复杂度分析:
时间复杂度:O(nlogn) 建堆的时间代价是 O(n),删除的总代价是 O(k \log n)
空间复杂度:O(k)
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int> q;
for (auto &num : nums){
q.push(num);
}
for (int i = 0; i < k - 1; ++i){
q.pop();
}
return q.top();
}
from heapq import *
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
minHeap = []
for i in range(k):
heappush(minHeap, nums[i])
for i in range(k, len(nums)):
if nums[i] > minHeap[0]:
heappushpop(minHeap, nums[i])
return minHeap[0]
思路:堆排序
class Solution {
//利用优先队列实现最小堆:遍历原数组的值,添加到堆中(想象成堆的容量为k)
//如果堆中元素的个数小于等于k的时候,我们就往堆中添加,
//添加之后如果堆中元素个数大于k的时候,我们就把最顶端的元素给移除掉,
//这样留到最后,最小堆堆顶的值正好就是第k大个数
public int findKthLargest(int[] nums, int k) {
//java优先队列默认就是优先取到小的元素,即小顶堆
PriorityQueue<Integer> queue = new PriorityQueue<>();
for(int val: nums){
queue.add(val);
if(queue.size() > k){
queue.poll();
}
}
return queue.peek();
}
}
时间复杂度:O(NlogN) 空间复杂度:O(N)
215. 数组中的第 K 个最大元素
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/kth-largest-element-in-an-array/
前置知识
题目描述
在未排序的数组中找到第 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 ≤ 数组的长度。