目录
239.滑动窗口最大值
题目
给你一个整数数组 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
代码
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
//123456 k=3 输出结果是6-3+1个
int[] res = new int[nums.length - k + 1];
int index = 0; //保存res的索引
//创建我的自定义队列
Mydeque deque = new Mydeque();
//先把前k个元素添加进去
for(int i=0; i < k ;i++){
deque.offer(nums[i]);
}
//第一个滑动窗口的最大值就在队头
res[index++] = deque.peek();
//处理后面的元素
for(int i = k; i < nums.length; i++){
//x是上一轮滑动窗口本来应该被移除的
int x = nums[i - k]; //321是上一轮的,x=3
deque.poll(x); //添加本一轮的0前,如果队头是3,把3弄掉
deque.offer(nums[i]); //把这轮的0加进来
res[index++] = deque.peek(); //获取这轮的队头最大值
}
return res;
}
}
class Mydeque{
Deque<Integer> deque = new ArrayDeque<>();
//peek获取队头元素,也就是当前窗口的最大值
public int peek(){
return deque.peek();
}
//队尾添加元素,需要把队列中比该元素小的都移除,512 添加3,要移除12
public void offer(int x){
while(!deque.isEmpty() && x > deque.peekLast()){
deque.pollLast(); //x大,就把队列末尾元素去除,x是大于,不是大于等于
}
deque.offer(x); //把x添加进去
}
//删除被滑动窗口移出的元素,x就是本来滑动窗口要删的
public void poll(int x){
//x == deque.peek() 说明队头元素就是我们要删的,321 新一轮滑动前 要把3删掉
//x != deque.peek() 123 12已经在3进队时poll了,此时队列只有3,下一轮滑动窗口要移除的x=1
if(!deque.isEmpty() && x == deque.peek()){
deque.poll();
}
}
}
代码(暴力解法,力扣会超时)
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int[] res = new int[nums.length - k + 1];
for(int i=0; i <= nums.length - k; i++){
int start = i;
int end = i + k - 1;
int big = getMax(nums,start,end);
res[i] = big;
}
return res;
}
public int getMax(int[] nums,int start,int end){
int max = nums[start];
for(int i = start; i <= end; i++){
if(nums[i] > max){
max = nums[i];
}
}
return max;
}
}
347.前K个高频元素
题目
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2]
代码(优先队列降序)
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>();
//遍历nums,存储频率的kv对
for(int i : nums){
//map.getOrDefault(i,0),如果有i返回value,没有i返回0
map.put(i,map.getOrDefault(i,0) + 1);
}
//创建优先队列,根据value进行降序排序,这里用了lambda表达式
PriorityQueue<int[]> pq = new PriorityQueue<>((o1,o2)-> o2[1] - o1[1]);
//遍历map的每一个entry转为数组
for(Map.Entry<Integer,Integer> entry : map.entrySet()){
int[] tmp = new int[2];
tmp[0] = entry.getKey();
tmp[1] = entry.getValue();
pq.offer(tmp); //把map对应的数组加到队列中,pq优先队列会自动排序
}
//保存前k个频率最高的key
int[] res = new int[k];
//遍历pq中前k个entry,获取前k个key
for(int i =0; i < k; i++){
res[i] = pq.poll()[0];
}
return res;
}
}
代码(List降序)
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>();
for(int i : nums){
map.put(i, map.getOrDefault(i,0) + 1);
}
//把map的每个entry转为list存储
List<Map.Entry<Integer,Integer>> list = new ArrayList<>(map.entrySet());
//用Collections.sort根据entry的Value进行降序排序
Collections.sort(list, (o1,o2) -> o2.getValue() - o1.getValue());
//保存前k个的key
int[] res = new int[k];
for (int i = 0; i < k; i++) {
//获取list的第i个entry
Map.Entry<Integer,Integer> entry = list.get(i);
//获取key
res[i]= entry.getKey();
}
return res;
}
}
代码(Stream流)
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> hm = new HashMap<>();
for(int i : nums){
hm.put(i,hm.getOrDefault(i,0)+1);
}
Integer[] arr = hm.keySet().stream()
.sorted((o1,o2) -> hm.get(o2) - hm.get(o1))
.limit(k)
.toArray(Integer[]::new);
int[] res = new int[k];
int index = 0;
for(Integer i : arr){
res[index++] = i;
}
return res;
}
}