代码随想录Day13|滑动窗口最大值 前K个高频元素
1.题目链接:滑动窗口最大值 - 力扣
题目描述:给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
示例 2:
输入:nums = [1], k = 1
输出:[1]
解题思路:
自己设置一个单调递减序列。加一些条件,设置队列弹出和弹入的方式。滑动窗口要求的是当前窗口的最大值,我们可以将最大的元素放在队首进行保留。在进行添加元素的操作时,可以让当前元素与队列中的元素进行比较,如果比队列的元素大,则将队列中的元素弹出,使得队列始终维持一个单调递减的状态。
比较小的元素弹出,并不影响最后的结果值,因为在那一个区间内的最大元素始终都是队列头。
取出每一次的队头(即滑动窗口的最大值),保存到结果数组中即可
下面是代码示例:
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length==1){
return nums;
}
int len= nums.length-k+1;
//存放结果元素的数组
int[] res=new int[len];
int num=0;
//自定义队列
MyQueue myQueue=new MyQueue();
//先将前k的元素放入队列
for(int i=0;i<k;i++){
myQueue.add(nums[i]);
}
res[num++]=myQueue.peek();
for(int i=k;i<nums.length;i++){
//滑动窗口移除最前面的元素,移除是判断该元素是否放入队列
myQueue.poll(nums[i-k]);
myQueue.add(nums[i]);
res[num++]=myQueue.peek();
}
return res;
}
}
class MyQueue{
Deque<Integer> deque=new LinkedList<>();
//重写了poll方法?
void poll(int val){
if(!deque.isEmpty()&&val==deque.peek()){
deque.poll();
}
}
void add(int val){
//因为是递减序列,所以从尾部开始比较
while(!deque.isEmpty()&&val>deque.getLast()){
deque.removeLast();
}
deque.add(val);
}
int peek(){
return deque.peek();
}
}
2.题目链接:前 K 个高频元素 - 力扣
题目描述:给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
解题思路:
这道题涉及到需要储存两个值,一个是数本身,一个是数出现的次数。一般看到这样的情况,可以选择使用map进行储存,key储存相对应的数,value存储数出现的次数。map统计好结果,将结果统计完后,接下来要做的就是进行排序了。
在java中可以使用优先队列的差值排序进行排序。使用map中的value值进行排序。整体思路是使用小顶堆,一开始只有k个元素的时候,直接放入队列中进行排序。当元素大于k个时,就需要与堆顶进行比较,因为使用的是小顶堆,如果把堆顶大,则将元素加入到优先队列中。最后倒序将堆放入到数组中并返回即可。
补充差值排序:差值排序指的是一种排序算法或排序方式,其中元素的相对顺序是通过比较它们之间的差值来确定的。在差值排序中,通常会定义一个比较器(Comparator),该比较器根据两个元素的某种属性值之间的差值来决定它们的顺序关系。
具体来说,当比较两个元素时,通过计算它们之间特定属性的差值,可以得到一个正数、负数或零。根据这个差值的符号以及大小,就可以确定哪个元素应该排在前面,哪个元素应该排在后面,以达到排序的目的。
下面是代码示例:
class Solution {
public int[] topKFrequent(int[] nums, int k) {
//key为数组元素的值,val为对应出现的次数
Map<Integer,Integer> map=new HashMap<>();
for(int num:nums){
map.put(num,map.getOrDefault(num,0)+1);
}
//在优先队列中储存二元组,使用小顶堆的方式进行储存,从小到大排,最低的出现在队头
//使用lambda表达式进行排序,优先级队列会根据整型数组中索引为 1 的元素的大小来确定元素的优先级顺序
//差值排序,小顶堆
PriorityQueue<int[]> pq=new PriorityQueue<>((pair1,pair2)->pair1[1]-pair2[1]);
//使用for循环遍历map中的每个键值对,并将每个键值对的键和值分别赋值给entry进行后续操作
//entrySet()方法返回一个包含map中所有键值对的集合
for(Map.Entry<Integer,Integer> entry: map.entrySet()){
if (pq.size()<k){
pq.add(new int[]{entry.getKey(),entry.getValue()});
}else{
if(entry.getValue()>pq.peek()[1]){
pq.poll();
pq.add(new int[]{entry.getKey(),entry.getValue()});
}
}
}
int[] ans=new int[k];
for (int i=k-1;i>=0;i--){
ans[i]=pq.poll()[0];
}
return ans;
}
}
总结:
今天学习的内容相对较难。一个是自己设置单调递减序列,一个是使用java里面自带的优先级队列。第一题相对来说,较为灵活,没有使用过这样的方式进行求解,还需要再多加学习。对于dequee队列的使用方法也还有很多没有掌握,平时还要多练习,才更好的记住一些比较常用的用法。 第二题利用的是优先队列,也是对java中自带的优先队列不太了解,以及map中的一些使用方法还不是很熟悉。对java的掌握还不够熟练。
总的来说,这两道题的思路都不算难,都利用到了java中自带的一些结构,还需要多学习多练习,逐渐掌握。
dequee队列的使用方法也还有很多没有掌握,平时还要多练习,才更好的记住一些比较常用的用法。 第二题利用的是优先队列,也是对java中自带的优先队列不太了解,以及map中的一些使用方法还不是很熟悉。对java的掌握还不够熟练。
总的来说,这两道题的思路都不算难,都利用到了java中自带的一些结构,还需要多学习多练习,逐渐掌握。
今天补周一的打卡