leecode更新

This commit is contained in:
dingjiawen 2022-09-16 12:51:56 +08:00
parent 26376573fb
commit 9afc59fc65
2 changed files with 130 additions and 1 deletions

View File

@ -165,7 +165,7 @@ public class MaxSlidingWindow {
/**
* 官方使用优先队列完成的做法:时间复杂度O(nlogn)
* 对于最大值我们可以想到一种非常合适的数据结构那就是优先队列其中的大根堆可以帮助我们实时维护一系列元素中的最大值
* 对于本题而言初始时我们将数组 nums 的前 kk 个元素放入优先队列中每当我们向右移动窗口时我们就可以把一个新的元素放入优先队列中此时堆顶的元素就是堆中所有元素的最大值然而这个最大值可能并不在滑动窗口中在这种情况下这个值在数组 nums 中的位置出现在滑动窗口左边界的左侧因此当我们后续继续向右移动窗口时这个值就永远不可能出现在滑动窗口中了我们可以将其永久地从优先队列中移除
* 对于本题而言初始时我们将数组 nums 的前 k 个元素放入优先队列中每当我们向右移动窗口时我们就可以把一个新的元素放入优先队列中此时堆顶的元素就是堆中所有元素的最大值然而这个最大值可能并不在滑动窗口中在这种情况下这个值在数组 nums 中的位置出现在滑动窗口左边界的左侧因此当我们后续继续向右移动窗口时这个值就永远不可能出现在滑动窗口中了我们可以将其永久地从优先队列中移除
* 我们不断地移除堆顶的元素直到其确实出现在滑动窗口中此时堆顶元素就是滑动窗口中的最大值为了方便判断堆顶元素与滑动窗口的位置关系我们可以在优先队列中存储二元组(num,index)表示元素 num 在数组中的下标为 index
* <p>
* TODO 本质上就是维护一个可以比较大小的优先队列,队列中存放(,索引)

View File

@ -0,0 +1,129 @@
package com.markilue.leecode.stackAndDeque;
import org.junit.Test;
import java.util.*;
/**
* @BelongsProject: Leecode
* @BelongsPackage: com.markilue.leecode.stackAndDeque
* @Author: dingjiawen
* @CreateTime: 2022-09-16 09:24
* @Description: TODO 力扣347题 前k个高频元素
* 给你一个整数数组 nums 和一个整数 k 请你返回其中出现频率前 k 高的元素你可以按 任意顺序 返回答案
* @Version: 1.0
*/
public class TopKFrequent {
@Test
public void test() {
int[] nums = {1, 1, 1, 2, 2, 3};
int k = 2;
int[] result = topKFrequent1(nums, k);
System.out.println(Arrays.toString(result));
}
@Test
public void test1() {
int[] nums = {1};
int k = 1;
int[] result = topKFrequent(nums, k);
System.out.println(Arrays.toString(result));
}
/**
* 自己的思路一:先给nums排序那么相同的数一定在临近然后遍历一遍获取count, ->如果使用数组进行记录则数组大小跟nums里最大的数有关,这里使用优先队列进行记录
* 整体时间复杂度O(nlogn),因为排序O(nlogn)遍历一遍O(n),放入优先队列O(logn)
* 速度击败99.59%,内存击败13.35%
*
* @param nums
* @param k
* @return
*/
public int[] topKFrequent(int[] nums, int k) {
Arrays.sort(nums);
int lastNum = nums[0];
int count = 0;
//使用优先队列记录<num,count>
PriorityQueue<int[]> deque = new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] nums1, int[] nums2) {
return nums1[1] != nums2[1] ? nums2[1] - nums1[1] : nums2[0] - nums1[0];
}
});
for (int i = 0; i < nums.length; i++) {
if (nums[i] == lastNum) {
count += 1;
}
if (nums[i] != lastNum) {
deque.offer(new int[]{lastNum, count});
count = 1;
lastNum = nums[i];
}
//如果是最后一个数了那就直接放
if (i == nums.length - 1) {
deque.offer(new int[]{nums[i], count});
}
}
int[] result = new int[k];
for (int i = 0; i < k; i++) {
result[i] = deque.poll()[0];
}
return result;
}
/**
* 官方思路:不用先排序,直接用map装<num,count>,装完以后遍历map,用一个小顶堆维护一个大小为k的堆少于k直接装大于k就和堆顶元素比
* map装复杂度O(n),取map O(1),堆大小只有k,所以堆化操作复杂度O(logk),所以最后时间复杂度O(nlogk)
* 速度超过94.94%内存超过25.05%
*/
public int[] topKFrequent1(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
//创建一个小顶堆
PriorityQueue<int[]> deque = new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] nums1, int[] nums2) {
return nums1[1] - nums2[1];
}
});
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
Integer num = entry.getKey();
Integer count = entry.getValue();
if(deque.size()<k){
deque.offer(new int[]{num,count});
}else {
if(count>deque.peek()[1]){
deque.poll();
deque.offer(new int[]{num,count});
}
}
}
int[] result = new int[k];
for (int i = 0; i < k; i++) {
result[i]=deque.poll()[0];
}
return result;
}
}