算法训练Day13|● 239. 滑动窗口最大值● 347.前 K 个高频元素● 总结

简介: 算法训练Day13|● 239. 滑动窗口最大值● 347.前 K 个高频元素● 总结

(leetcode)LeetCode: 239. 滑动窗口最大值

滑动窗口最大值-力扣(leetcode)

1.思路一

滑动窗口最大值:两层for循环暴力遍历求解;(结果当然是超时…)

2.代码实现

 1class Solution {
 2    public int[] maxSlidingWindow(int[] nums, int k) {
 3
 4        int[] res = new int[nums.length];
 5        if (nums.length >= k) {
 6            for (int i = 0; i < nums.length; i++) {
 7                while (i + k <= nums.length) {
 8
 9                    int temp = Integer.MIN_VALUE;
10                    for (int j = i; j < i + k; j++) {
11                        // 遍历出数组中的最大值???
12                        res[i] = Math.max(temp, nums[j]);
13
14                    }
15                }
16            }
17        }
18        return res;
19    }
20}


3.复杂度分析

时间复杂度:两层for循环,O(n) * O(m),则时间复杂度简化为O(n²).

空间复杂度:创建数组res,则空间复杂度为O(n).

1.思路二

借用单调队列的弹出、加入等操作记录窗口内最大值,妙不可言~

2.代码实现

 1class Solution {
 2    public int[] maxSlidingWindow(int[] nums, int k) {
 3
 4
 5        int len = nums.length - k + 1; // 预期结果数组长度
 6        int[] res = new int[len]; // 创建结果数组
 7        // 新数组索引为num
 8        int num = 0;
 9        // 前k个数组元素加入队列中
10        MyQueue myQueue = new MyQueue();
11        for (int i = 0; i < k; i++) {
12            myQueue.add(nums[i]);
13        }
14        // 将最大值存储到数组中
15        res[num++] = myQueue.peek();
16        // 窗口从k开始遍历
17        for (int i = k; i < nums.length; i++) {
18
19            // 出队列
20            myQueue.poll(nums[i - k]);
21            // 入队列
22            myQueue.add(nums[i]); // 入队的是当前元素!!!
23            // 记录结果
24            res[num++] = myQueue.peek();
25        }
26        return res;
27
28    }
29}
30
31class MyQueue {
32    Deque<Integer> deque = new LinkedList<>();
33
34    public void poll(int val) {
35        if (!deque.isEmpty() && val == deque.peek()) {
36            deque.poll();
37        }
38    }
39
40    public void add(int val) {
41        while (!deque.isEmpty() && val > deque.peek()) {
42            deque.removeLast();
43        }
44        deque.add(val);
45    }
46
47    public int peek() {
48        return deque.peek();
49    }
50}

3.复杂度分析

时间复杂度:一层for循环解决,则复杂度为O(n).

空间复杂度:创建了一个队列,则复杂度为O(n).

4.参考

代码随想录(progarmmercarl.com)

LeetCode: 347.前 K 个高频元素

347.前K个高频元素-力扣(leetcode)

1.思路:

思路①:两层for循环,一层遍历记录,一层交换;

思路②:

2.代码实现

 1// 未实现
 2class Solution {
 3    public int[] topKFrequent(int[] nums, int k) {
 4        // 一层for循环将其出现的频率记录,需要定义一个数组记录,怎么记录??map好像可以
 5        int len = nums.length;
 6        int[] res = new int[len];
 7        for (int i = 0; i < len; i++) {
 8
 9        }
10        // 一层for循环将前k个元素记录返回即可
11        Arrays.sort(res);
12        int[] nums1 = new nums1[k];
13        for (int i = 0; i < res.length; i++) {
14            nums1[i] = res[i];
15        }
16        return nums1;
17    }
18}
19
20// 正确使用map的姿势
21class Solution {
22    public int[] topKFrequent(int[] nums, int k) {
23        // 使用 HashMap 统计每个数字出现的次数
24        Map<Integer, Integer> occurrences = new HashMap<Integer, Integer>();
25        for (int num : nums) {
26            occurrences.put(num, occurrences.getOrDefault(num, 0) + 1);
27        }
28
29        // 使用优先队列(最小堆)来存储出现次数最大的 k 个数字
30        // int[] 的第一个元素代表数组的值,第二个元素代表了该值出现的次数
31        PriorityQueue<int[]> queue = new PriorityQueue<int[]>(new Comparator<int[]>() {
32            public int compare(int[] m, int[] n) {
33                return m[1] - n[1]; // 按照出现次数升序排序
34            }
35        });
36
37        // 遍历 HashMap 中的每个键值对
38        for (Map.Entry<Integer, Integer> entry : occurrences.entrySet()) {
39            int num = entry.getKey(); // 数字
40            int count = entry.getValue(); // 出现次数
41
42            // 如果优先队列已经有 k 个元素,则判断当前数字的出现次数是否大于队列中的最小值
43            // 如果是,则将队列中出现次数最小的元素出队,将当前数字入队
44            if (queue.size() == k) {
45                if (queue.peek()[1] < count) {
46                    queue.poll();
47                    queue.offer(new int[]{num, count});
48                }
49            } else { // 如果优先队列还没有 k 个元素,则直接将当前数字入队
50                queue.offer(new int[]{num, count});
51            }
52        }
53
54        // 构造结果数组,将队列中的元素按照出现次数从大到小依次出队并放入结果数组中
55        int[] ret = new int[k];
56        for (int i = 0; i < k; ++i) {
57            ret[i] = queue.poll()[0];
58        }
59
60        return ret;
61    }
62}

3.复杂度分析

时间复杂度:一层map遍历,记作O(n),一层小顶堆遍历,记作O(logk),n个数组共记作O(nlogk).

空间复杂度:创建一个map,为O(n),创建一个队列,为O(k),创建一个数组,为O(k),故整体记作O(n).

4.参考

代码随想录(programmercarl.com)

总结:

栈:先进后出(后进先出)递归的实现是栈:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中。


栈经典题目

括号匹配:是使用栈解决的经典问题。

字符串去重:可以把字符串顺序放到一个栈中,然后如果相同的话 栈就弹出,这样最后栈里剩下的元素都是相邻不相同的元素了。

逆波兰表达式问题:字符串去重逻辑一致。

三者处理逻辑相似,可以模板化。不同在于细节操作方式。


队列经典题目

队列:分为单边队列(Queue)和双边队列(Deque),单边队列:先进先出。双端队列,前后两端均可进出。故可以当作栈使用。

滑动窗口最大值:队列采用弹出、加入操作实现对滑动窗口的移动和最值操作。加入和弹出操作细节有点绕。加入:需要循环判断入口值和当前值比较,如果当前值大于入口值,则弹出队列中所有小于当前值的值,直到入口值比当前值大.弹出:如果值等于入口值弹出,不等于则不操作,因为在加入的时候就对其进行比较操作了。

求前 K 个高频元素:思路很清晰,实现很陌生。需要使用map集合(记得前面刷题有遇到相似的情况)记录遍历之后的每个元素的频率。对其排序遍历返回即可


相关文章
|
12天前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
30 3
|
3月前
|
算法
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
|
20天前
|
存储 机器学习/深度学习 算法
蓝桥杯练习题(三):Python组之算法训练提高综合五十题
蓝桥杯Python编程练习题的集合,涵盖了从基础到提高的多个算法题目及其解答。
36 3
蓝桥杯练习题(三):Python组之算法训练提高综合五十题
|
13天前
|
存储 算法 Java
Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定数据结构和算法确保元素唯一性
Java Set因其“无重复”特性在集合框架中独树一帜。本文解析了Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定数据结构和算法确保元素唯一性,并提供了最佳实践建议,包括选择合适的Set实现类和正确实现自定义对象的hashCode()与equals()方法。
29 4
|
25天前
|
机器学习/深度学习 算法 决策智能
【机器学习】揭秘深度学习优化算法:加速训练与提升性能
【机器学习】揭秘深度学习优化算法:加速训练与提升性能
|
27天前
|
算法 Java C++
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
|
27天前
|
算法 C++
蓝桥 算法训练 共线(C++)
蓝桥 算法训练 共线(C++)
|
3月前
|
算法 搜索推荐
支付宝商业化广告算法问题之基于pretrain—>finetune范式的知识迁移中,finetune阶段全参数训练与部分参数训练的效果如何比较
支付宝商业化广告算法问题之基于pretrain—>finetune范式的知识迁移中,finetune阶段全参数训练与部分参数训练的效果如何比较
|
7天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
4天前
|
人工智能 算法 数据安全/隐私保护
基于遗传优化的SVD水印嵌入提取算法matlab仿真
该算法基于遗传优化的SVD水印嵌入与提取技术,通过遗传算法优化水印嵌入参数,提高水印的鲁棒性和隐蔽性。在MATLAB2022a环境下测试,展示了优化前后的性能对比及不同干扰下的水印提取效果。核心程序实现了SVD分解、遗传算法流程及其参数优化,有效提升了水印技术的应用价值。