代码随想录算法训练营第十一天 | 150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素、栈与队列总结
150. 逆波兰表达式求值--后缀表达式
力扣题目链接(opens new window)
根据 逆波兰表示法,求表达式的值。
有效的运算符包括 + , - , * , / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
- 输入: ["2", "1", "+", "3", " * "]
- 输出: 9
- 解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
逆波兰表达式:是一种后缀表达式,所谓后缀就是指运算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
-
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
-
适合用栈操作运算:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中。
思路
递归就是用栈来实现的。所以栈与递归之间在某种程度上是可以转换的!
那么来看一下本题,其实逆波兰表达式相当于是二叉树中的后序遍历。 大家可以把运算符作为中间节点,按照后序遍历的规则画出一个二叉树。
但我们没有必要从二叉树的角度去解决这个问题,只要知道逆波兰表达式是用后序遍历的方式把二叉树序列化了,就可以了。
遇到运算符弹出栈顶两个元素进行运算,运算结果放回栈顶;遇到数字直接入栈。
题外话
我们习惯看到的表达式都是中缀表达式,因为符合我们的习惯,但是中缀表达式对于计算机来说就不是很友好了。
例如:4 + 13 / 5,这就是中缀表达式,计算机从左到右去扫描的话,扫到13,还要判断13后面是什么运算符,还要比较一下优先级,然后13还和后面的5做运算,做完运算之后,还要向前回退到 4 的位置,继续做加法,你说麻不麻烦!
那么将中缀表达式,转化为后缀表达式之后:["4", "13", "5", "/", "+"] ,就不一样了,计算机可以利用栈来顺序处理,不需要考虑优先级了。也不用回退了, 所以后缀表达式对计算机来说是非常友好的。
补充:java中的栈
Java中栈的实现方式对比
实现方式 | 所属包/类 | 线程安全 | 性能 | 功能特点 | 适用场景 | 不适用场景 |
---|---|---|---|---|---|---|
Stack 类 | java.util.Stack | 是(继承Vector) | 较差(同步开销) | 提供完整的栈操作(push/pop/peek ),但继承了Vector 的冗余方法 | 需要线程安全的简单栈操作 | 高并发或高性能场景 |
ArrayDeque | java.util.ArrayDeque | 否 | 最优(动态数组实现) | 实现了Deque 接口,可模拟栈(push/pop )或队列 | 推荐:单线程环境下需要高性能的栈操作 | 需要线程安全的场景 |
LinkedList | java.util.LinkedList | 否 | 中等(链表节点开销) | 实现了Deque 接口,支持栈操作(push/pop ) | 需要频繁插入/删除或不确定容量时 | 需要快速随机访问的场景 |
自定义栈 | 自行实现(如基于数组或链表) | 取决于实现 | 可优化 | 完全控制内部逻辑和扩展性 | 需要特殊功能(如固定大小栈、最小栈等) | 追求开发效率时 |
使用stack类:
操作类型 | 方法 | 描述 | 返回值 | 异常 |
---|---|---|---|---|
压栈操作 | E push(E item) | 将元素压入栈顶 | 被压入的元素 | - |
弹栈操作 | E pop() | 移除并返回栈顶元素 | 栈顶元素 | EmptyStackException (栈为空时) |
查看栈顶 | E peek() | 返回栈顶元素(不移除) | 栈顶元素 | EmptyStackException (栈为空时) |
检查空栈 | boolean empty() | 检查栈是否为空 | true (空栈)/false (非空) | - |
搜索元素 | int search(Object o) | 查找元素在栈中的位置(从栈顶开始计数,1为栈顶) | 元素位置(从1开始)/-1(未找到) | - |
获取大小 | int size() | 返回栈中元素数量 | 元素数量 | - |
获取元素 | E get(int index) | 获取指定索引处的元素(0为栈底,size()-1为栈顶) | 指定位置的元素 | IndexOutOfBoundsException (索引越界时) |
清空栈 | void clear() | 移除栈中所有元素 | - | - |
Java 中的 Deque
接口代表双向队列(Double-ended Queue),它允许在队列的两端(头部和尾部)高效地插入、删除和访问元素。
在 Java 中,Deque
和 ArrayDeque
是接口与实现类的关系,它们共同提供了双向队列(Double-ended Queue)的功能。
Deque
接口实现栈的方法对照表
定义:Deque<String> stack = new ArrayDeque<>();
栈操作 | Deque 方法 | 等效 Stack 类方法 | 功能描述 | 异常/返回值 |
---|---|---|---|---|
压栈 (Push) | void push(E e) | E push(E item) | 将元素压入栈顶 | 失败时抛出 IllegalStateException (容量受限时) |
弹栈 (Pop) | E pop() | E pop() | 移除并返回栈顶元素 | 空栈时抛出 NoSuchElementException |
查看栈顶 (Peek) | E peek() | E peek() | 返回栈顶元素(不移除) | 空栈时返回 null |
检查空栈 | boolean isEmpty() | boolean empty() | 判断栈是否为空 | true (空栈)/false (非空) |
获取栈大小 | int size() | int size() | 返回栈中元素数量 | - |
Deque
的实现类对比
实现类 | 底层结构 | 线程安全 | 性能 | 适用场景 |
---|---|---|---|---|
ArrayDeque | 动态数组 | 否 | 最优 | 默认选择(单线程高性能栈) |
LinkedList | 双向链表 | 否 | 中等 | 需要频繁增删或同时作为队列使用 |
用 Deque实现双向队列
Deque<String> stack = new ArrayDeque<>();
由于使用了 Deque
接口类型,它能调用所有双向队列的方法。以下是双向队列的核心操作总结:
双向队列操作总结表
操作类型 | 头部方法(First/Front) | 尾部方法(Last/Back) | 说明 |
---|---|---|---|
插入元素 | addFirst(E e) offerFirst(E e) | addLast(E e) offerLast(E e) | 插入失败时: - addXXX() 抛出异常- offerXXX() 返回 false |
删除元素 | removeFirst() pollFirst() | removeLast() pollLast() | 队列为空时: - removeXXX() 抛出异常- pollXXX() 返回 null |
查看元素 | getFirst() peekFirst() | getLast() peekLast() | 队列为空时: - getXXX() 抛出异常- peekXXX() 返回 null |
栈操作(LIFO) | push(E e) (等价于 addFirst ) | pop() (等价于 removeFirst ) | 后进先出(栈的特性) |
队列操作(FIFO) | offer(E e) (等价于 offerLast ) | poll() (等价于 pollFirst ) | 先进先出(普通 |
class Solution {public int evalRPN(String[] tokens) {Deque<Integer> stack = new ArrayDeque<>();for(String s: tokens){if("+".equals(s)){ // leetcode 内置jdk的问题,不能使用==判断字符串是否相等stack.push( stack.pop() + stack.pop() );}else if("-".equals(s)){stack.push( -stack.pop() + stack.pop() );}else if("*".equals(s)){stack.push( stack.pop() * stack.pop() );}else if("/".equals(s)){int tmp1 = stack.pop();int tmp2 = stack.pop();stack.push(tmp2 / tmp1);}else{ //数字直接入栈stack.push(Integer.valueOf(s));}}return stack.pop();}
}
#239. 滑动窗口最大值
力扣题目链接(opens new window)
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
进阶:
你能在线性时间复杂度内解决此题吗?
提示:
- 1 <= nums.length <= 10^5
- -10^4 <= nums[i] <= 10^4
- 1 <= k <= nums.length
思路
这是使用单调队列的经典题目。
不能使用优先级队列(大顶堆):底层使用二叉树,插入时自动排序,poll弹出时自动弹出最小值。
补充:java中的优先级队列
在 Java 里,优先级队列(PriorityQueue
)的底层实现是最小堆(也被叫做二叉堆)。
- 插入操作(
offer
):时间复杂度为 (O(log n))。在插入元素后,需要对堆进行调整,以维持堆的特性。 - 删除操作(
poll
):时间复杂度同样是 \(O(\log n)\)。删除最小元素后,要重新调整堆结构。 - 查看操作(
peek
):时间复杂度为 \(O(1)\),因为队列头部的元素就是最小元素。
下面是一个简单的代码示例,展示了 PriorityQueue
的基本用法:
import java.util.PriorityQueue;
import java.util.Comparator;public class PriorityQueueExample {public static void main(String[] args) {// 自然顺序(最小堆)PriorityQueue<Integer> minHeap = new PriorityQueue<>();minHeap.offer(3);minHeap.offer(1);minHeap.offer(2);System.out.println(minHeap.poll()); // 输出: 1// 自定义比较器(最大堆)PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());maxHeap.offer(3);maxHeap.offer(1);maxHeap.offer(2);System.out.println(maxHeap.poll()); // 输出: 3}
}
所以需要自己DIY一种队列--单调队列!
作用:可以维护队列中的元素顺序,但是push、pop时还是弹出栈顶的元素,而不是排序后的元素
只维护可能成为最大值的元素
那么问题来了,已经排序之后的队列 怎么能把窗口要移除的元素(这个元素可不一定是最大值)弹出呢。
大家此时应该陷入深思.....
其实队列没有必要维护窗口里的所有元素,只需要维护有可能成为窗口里最大值的元素就可以了,同时保证队列里的元素数值是由大到小的。
那么这个维护元素单调递减的队列就叫做单调队列,即单调递减或单调递增的队列。C++中没有直接支持单调队列,需要我们自己来实现一个单调队列
不要以为实现的单调队列就是 对窗口里面的数进行排序,如果排序的话,那和优先级队列又有什么区别了呢。
来看一下单调队列如何维护队列里的元素。
动画如下:
对于窗口里的元素{2, 3, 5, 1 ,4},单调队列里只维护{5, 4} 就够了,保持单调队列里单调递减,此时队列出口元素就是窗口里最大元素。
此时大家应该怀疑单调队列里维护着{5, 4} 怎么配合窗口进行滑动呢?
设计单调队列的时候,pop,和push操作要保持如下规则:
- pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
- push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止
保持如上规则,每次窗口移动的时候,只要问que.front()就可以返回当前窗口的最大值。
为了更直观的感受到单调队列的工作过程,以题目示例为例,输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3,动画如下:
那么我们用什么数据结构来实现这个单调队列呢?
使用deque最为合适
错误第一版代码:
class Solution {public static Deque<Integer> slidingWin = new ArrayDeque<>();public int[] maxSlidingWindow(int[] nums, int k) {if(k == 1 )return nums;int res[] = new int[nums.length - k + 1];for(int i = 0; i < k; i++){ pushthis(nums[i]);}for(int i = 0; i < nums.length - k + 1; i++){ //滑动过程popfront(nums[i]);pushthis(nums[i + k - 1]);res[i] = getMaxVal();}return res;}private void popfront(int value){ //value是当前需要pop的值if( !slidingWin.isEmpty() && value == getMaxVal()){ //只有在当前值是最大值时才弹出slidingWin.pop();}}private void pushthis(int value){ //value是当前需要push的值while( !slidingWin.isEmpty() && slidingWin.peekLast() < value ){ //弹出双向队列后面所有比val小的值slidingWin.pollLast();}slidingWin.offerLast(value);}private int getMaxVal(){ //获取当前窗口的最大值--即栈顶return slidingWin.peekFirst();}
}
正确版本:
//解法一
//自定义数组
class MyQueue {Deque<Integer> deque = new LinkedList<>();//弹出元素时,比较当前要弹出的数值是否等于队列出口的数值,如果相等则弹出//同时判断队列当前是否为空void poll(int val) {if (!deque.isEmpty() && val == deque.peek()) {deque.poll();}}//添加元素时,如果要添加的元素大于入口处的元素,就将入口元素弹出//保证队列元素单调递减//比如此时队列元素3,1,2将要入队,比1大,所以1弹出,此时队列:3,2void add(int val) {while (!deque.isEmpty() && val > deque.getLast()) {deque.removeLast();}deque.add(val);}//队列队顶元素始终为最大值int peek() {return deque.peek();}
}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;}
}//解法二
//利用双端队列手动实现单调队列
/*** 用一个单调队列来存储对应的下标,每当窗口滑动的时候,直接取队列的头部指针对应的值放入结果集即可* 单调递减队列类似 (head -->) 3 --> 2 --> 1 --> 0 (--> tail) (左边为头结点,元素存的是下标)*/
class Solution {public int[] maxSlidingWindow(int[] nums, int k) {ArrayDeque<Integer> deque = new ArrayDeque<>();int n = nums.length;int[] res = new int[n - k + 1];int idx = 0;for(int i = 0; i < n; i++) {// 根据题意,i为nums下标,是要在[i - k + 1, i] 中选到最大值,只需要保证两点// 1.队列头结点需要在[i - k + 1, i]范围内,不符合则要弹出while(!deque.isEmpty() && deque.peek() < i - k + 1){deque.poll();}// 2.维护单调递减队列:新元素若大于队尾元素,则弹出队尾元素,直到满足单调性while(!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {deque.pollLast();}deque.offer(i);// 因为单调,当i增长到符合第一个k范围的时候,每滑动一步都将队列头节点放入结果就行了if(i >= k - 1){res[idx++] = nums[deque.peek()];}}return res;}
}
347.前 K 个高频元素
力扣题目链接(opens new window)
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
- 输入: nums = [1,1,1,2,2,3], k = 2
- 输出: [1,2]
示例 2:
- 输入: nums = [1], k = 1
- 输出: [1]
提示:
- 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
- 你的算法的时间复杂度必须优于 $O(n \log n)$ , n 是数组的大小。
- 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
- 你可以按任意顺序返回答案。
思路
这道题目主要涉及到如下三块内容:
- 要统计元素出现频率
- 对频率排序
- 找出前K个高频元素
首先统计元素出现的频率,这一类的问题可以使用map来进行统计。
然后是对频率进行排序,这里我们可以使用一种 容器适配器就是优先级队列。
大顶堆、小顶堆--适合求前k个结果
用大顶堆遍历一遍pop,剩下的是前K个低频元素。所以使用小顶堆
寻找前k个最大元素流程如图所示:(图中的频率只有三个,所以正好构成一个大小为3的小顶堆,如果频率更多一些,则用这个小顶堆进行扫描)
class Solution {public int[] topKFrequent(int[] nums, int k) {// 优先级队列,为了避免复杂 api 操作,pq 存储数组// lambda 表达式设置优先级队列从大到小存储 o1 - o2 为从小到大,o2 - o1 反之PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o1[1] - o2[1]);int[] res = new int[k]; // 答案数组为 k 个元素Map<Integer, Integer> map = new HashMap<>(); // 记录元素出现次数for (int num : nums) map.put(num, map.getOrDefault(num, 0) + 1);for (var x : map.entrySet()) { // entrySet 获取 k-v Set 集合// 将 kv 转化成数组int[] tmp = new int[2];tmp[0] = x.getKey();tmp[1] = x.getValue();pq.offer(tmp);// 下面的代码是根据小根堆实现的,我只保留优先队列的最后的k个,只要超出了k我就将最小的弹出,剩余的k个就是答案if(pq.size() > k) {pq.poll();}}for (int i = 0; i < k; i++) {res[i] = pq.poll()[0]; // 获取优先队列里的元素}return res;}
}
栈与队列总结篇
代码随想录
#栈与队列的理论基础
1. java中的stack和queue
Stack
:Java 中有一个继承自Vector
的具体类java.util.Stack
(线程安全但性能较差,不推荐使用)。现代 Java 中更常用Deque
接口(如ArrayDeque
)来实现栈功能。Queue
:Java 中的Queue
是一个接口(继承自Collection
),常见实现类有LinkedList
、PriorityQueue
等。
2.
特性 | Java 集合框架 | C++ STL |
---|---|---|
核心机制 | 接口 + 实现类(面向对象) | 模板(泛型编程) |
线程安全 | 部分类线程安全(如 Vector ) | 大部分非线程安全 |
栈实现 | Deque (推荐)或 Stack 类 | std::stack (适配器类) |
队列实现 | Queue 接口(如 LinkedList ) | std::queue (适配器类) |
3. Java 中 Stack
和 Queue
的实现方式
栈(Stack)
- 传统实现:
java.util.Stack
继承自Vector
,内部使用动态数组存储元素,所有操作通过synchronized
保证线程安全(但性能差)。 - 现代实现:推荐使用
Deque
接口(如ArrayDeque
或LinkedList
),通过push()
、pop()
、peek()
方法实现栈功能。ArrayDeque
:基于动态数组,无容量限制,性能最优。LinkedList
:基于双向链表,适合频繁插入 / 删除。
队列(Queue)
- 普通队列:
LinkedList
(基于链表)或ArrayDeque
(基于数组)。 - 优先队列:
PriorityQueue
(基于最小堆)。 - 阻塞队列:
LinkedBlockingQueue
、ArrayBlockingQueue
等(用于并发编程)
4. stack,queue 提供迭代器来遍历空间么?
栈(Stack)
java.util.Stack
:继承自Vector
,支持iterator()
,但遍历时顺序为 栈底到栈顶(与弹出顺序相反)。Deque
实现的栈:iterator()
:从队首(栈底)到队尾(栈顶)。descendingIterator()
:从队尾(栈顶)到队首(栈底)。
队列(Queue)
- 普通队列:
iterator()
按元素入队顺序遍历(FIFO)。 - 优先队列:
PriorityQueue
的迭代器不保证元素的优先级顺序,仅用于快速遍历。
在C++中,可以出一道面试题:栈里面的元素在内存中是连续分布的么?
这个问题有两个陷阱:
- 陷阱1:栈是容器适配器,底层容器使用不同的容器,导致栈内数据在内存中不一定是连续分布的。
- 陷阱2:缺省情况下,默认底层容器是deque,那么deque在内存中的数据分布是什么样的呢? 答案是:不连续的,下文也会提到deque。
在java中,
ArrayDeque
(基于动态数组)
-
内存分布:连续。
-
原理:
ArrayDeque
内部使用动态数组存储元素,数组在内存中是连续分配的。
LinkedList
(基于双向链表)
- 内存分布:不连续。
- 原理:
LinkedList
由节点(Node)组成,每个节点包含元素值和指向前驱 / 后继节点的引用。节点在内存中是离散分配的,通过引用连接。
传统 java.util.Stack
- 内存分布:连续。
- 原理:
Stack
继承自Vector
,内部使用动态数组存储元素,因此内存连续。
相关文章:

代码随想录算法训练营第十一天 | 150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素、栈与队列总结
150. 逆波兰表达式求值--后缀表达式 力扣题目链接(opens new window) 根据 逆波兰表示法,求表达式的值。 有效的运算符包括 , - , * , / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。 说明: 整数除法只保留整数部分。 给…...
Java编程课(一)
Java编程课 一、java简介二、Java基础语法2.1 环境搭建2.2 使用Intellij IDEA新建java项目2.3 Java运行介绍2.4 参数说明2.5 Java基础语法2.6 注释2.7 变量和常量一、java简介 Java是一种广泛使用的高级编程语言,最初由Sun Microsystems于1995年发布。它被设计为具有简单、可…...

IDEA202403 设置主题和护眼色
文章目录 背景一、设置主题二、设置背景豆沙绿三、设置控制台颜色 背景 在用IDEA进行开发时,长时间对着屏幕,不费眼是及其重要 一、设置主题 默认的主题是 Dark 暗黑,可更改为其他,如Light 高亮 位置:编辑栏【files…...

无人机螺旋桨平衡方法详解
螺旋桨平衡对于优化无人机性能、可靠性和使用寿命至关重要。不平衡的螺旋桨会产生过度振动,导致推力效率降低、噪音增大,并加速轴承和传感器的磨损。 螺旋桨平衡可通过三种方式实现:静态平衡、动态平衡和气动平衡。 静态与动态平衡是通过在…...
VUE混合开发用哪个PHP框架好?
在 Vue.js 主导前端的混合开发浪潮中,一个强大、灵活的后端 API 提供者至关重要。PHP 作为经久不衰的服务器端语言,拥有众多优秀框架。但哪个才是 Vue 混合开发的黄金搭档?本文将深入分析主流 PHP 框架的优劣,帮你找到最适合的那个…...

基于51单片机的车内防窒息检测报警系统
目录 具体实现功能 设计介绍 资料内容 全部内容 资料获取 具体实现功能 具体实现功能: (1)检测车内温度及二氧化碳浓度并用lcd1602实时显示。 (2)当人体红外传感器检测到车内有人,且温度或二氧化碳浓度…...

Flask-Babel 使用示例
下面创建一个简单的 Flask-Babel 示例,展示如何在 Flask 应用中实现国际化和本地化功能。这个示例将包括多语言支持(中文和英文)、语言切换功能以及翻译文本的使用。 项目结构 我们将创建以下文件结构: 1. 首先,创…...
Android 轻松实现 增强版灵活的 滑动式表格视图
表格视图组件,支持: 1. 无标题模式:只有数据行也可以正常滑动 2. 两种滑动模式:固定第一列 或 全部滑动 3. 全面的样式自定义能力 4. 智能列宽计算 1. 无标题模式支持 设置无标题:调用 setHeaderData(null) 或 …...
寄存器模型生成:从手工到自动化
写代码这件事,总是充满了矛盾。你想要完美控制每一个细节,但又希望能够批量生产。寄存器模型的生成,恰恰体现了这种矛盾。 手工编写的局限性 我们完全可以手工编写一个寄存器模型。代码写出来,功能也能实现,看起来一切…...

国标GB28181视频平台EasyGBS视频实时监控系统打造换热站全景可视化管理方案
一、方案背景 在城市供热体系中,换热站作为连接热源与用户的核心枢纽,其运行稳定性直接影响供热质量。面对供热规模扩大与需求升级,传统人工巡检模式暴露出效率低、响应慢、监测不足等问题。基于GB28181协议的EasyGBS视频实时监控系统&…...

docker生命周期
进入容器里面 docker pull ubuntu # 获取ubtuntu镜像 docker run ubtuntu # -i 交互式命令操作,-t 开启一个终端 bash 进入容器后,执行的命令 docker run -it ubtuntu bash...

鸿蒙缺少WMIC missing WMIC
在DecEco Studio中选择模拟器的时候会弹出“可能会导致设备管理功能失效。请检查并安装 WMIC”。 在启动鸿蒙模拟器时报:missing WMIC missing WMIC lt may cause the device management function to fail. Please check and install WMIC. 解决方案:…...
25.6.5学习总结
归并排序(Merge Sort) 1. 概述 归并排序是一种基于分治思想的排序算法。它通过递归的方式,将待排序的数组不断分割成两半,直到每个子数组只剩一个元素(自然排序);然后,将这些子数组…...

Spring Boot 使用 SLF4J 实现控制台输出与分类日志文件管理
概述 在日常的 Java 项目开发中,日志是最重要的调试与排查手段之一。为了便于开发时实时查看,同时在生产中追踪问题,我们通常希望实现以下日志管理目标: ✅ 控制台实时输出日志,方便开发调试✅ 日志根据级别分类保存…...

linux_centos7.x的ifconfig命令显示内容详解
这是一段在Linux系统中执行 ifconfig 命令后得到的网络接口信息输出。ifconfig 命令用于显示或配置网络接口的参数。以下是对输出中各个网络接口信息的详细解释: 1. ens33 接口 状态标志:flags4163<UP,BROADCAST,RUNNING,MULTICAST> 表示…...

CentOS 7 如何pip3安装pyaudio?
CentOS 7 如何pip3安装pyaudio? # 先将yum软件源改为阿里云镜像源 http://mirrors.aliyun.com/centos-vault/7.9.2009/ bash <(curl -sSL https://linuxmirrors.cn/main.sh) # 基于一键换源脚本,全部回车即可# pip3安装模块是从源码构建(…...
6.5本日总结
一、英语 复习默写list8list21,订正翻译07年第二篇阅读 二、数学 学习线代第一讲 三、408 学习计组2.2,写计组习题 四、总结 这篇阅读全对,整体题目不算难,但是对文意的翻译差点,后续要多练习句子翻译 五、明日…...

【个人笔记】数据库原理(西电)
第一章 ER图和关系分解见课本p69 ER图是常用的 概念模型 方形:实体圆形:属性菱形:关系 常用的逻辑模型 说白了:增删改查 几种数据模型的基本概念 层次模型:树状结构【只能处理一对多的关系,只有沿着从根…...

嵌入式学习之系统编程(十)网络编程之TCP传输控制协议
目录 一、网络模型 1、服务器/客户端模型 2、C/S与B/S区别 3、P2P模型 二、TCP(传输控制协议) (一)TCP概述 (二)TCP的特征(面问高频问题) 1、有链接 三次握手:建…...

【react+antd+vite】优雅的引入svg和阿里巴巴图标
1.安装相关包 由于是vite项目,要安装插件来帮助svg文件引入进来,否则会失败 npm下载包 npm i vite-plugin-svgr vite.config.ts文件内: import svgr from "vite-plugin-svgr"; //... export default defineConfig({plugins: …...

3D动画在微信小程序的实现方法
微信小程序支持通过多种方式实现3D动画效果,主要包括使用CSS3、WebGL及第三方库。以下为具体方法: 一. 使用CSS3 Transform实现基础3D动画详解 CSS3的transform属性提供了强大的2D/3D变换功能,通过简单的代码就能实现复杂的视觉效果。在小程…...

计算机网络 | 1.2 计算机网络体系结构与参考模型
计算机网络体系结构与参考模型 目录 计算机网络体系结构与参考模型 【思维导图】 1、计算机的分层结构 1、为什么要分层? 2、什么是计算机网络体系结构 2、计算机网络协议、接口和服务 1)协议: 2)接口: 3…...

网心云 OEC/OECT 笔记(1) 拆机刷入Armbian固件
目录 网心云 OEC/OECT 笔记(1) 拆机刷入Armbian固件网心云 OEC/OECT 笔记(2) 运行RKNN程序 外观 内部 PCB正面 PCB背面 PCB背面 RK3566 1Gbps PHY 配置 OEC 和 OECT(OEC-turbo) 都是基于瑞芯微 RK3566/RK3568 的网络盒子, 没有HDMI输入输出. 硬件上 OEC 和 OECT…...

【Web应用】若依框架:基础篇17二次开发-项目名称修改-新建业务模块
文章目录 ⭐前言⭐一、课程讲解⭐二、自己手动实操⭐总结 标题详情作者JosieBook头衔CSDN博客专家资格、阿里云社区专家博主、软件设计工程师博客内容开源、框架、软件工程、全栈(,NET/Java/Python/C)、数据库、操作系统、大数据、人工智能、工控、网络、…...
C获取unix操作系统的信息
在 C 语言中获取 Linux 操作系统的架构类型(如 x86_64)、系统位数(32/64位)、内核信息等,可以通过多种方式实现。下面是几种常见的方法: ✅ 方法一:使用 uname 获取系统信息 #include <stdio.h> #include <sys/utsname.h>int main(...

MQTT入门实战宝典:从零起步掌握物联网核心通信协议
MQTT入门实战宝典:从零起步掌握物联网核心通信协议 前言 物联网时代,万物互联已成为现实,而MQTT协议作为这个时代的"数据总线",正默默支撑着从智能家居到工业物联的各类应用场景。本文将带你揭开MQTT的神秘面纱&#…...

05【Linux经典命令】Linux 用户管理全面指南:从基础到高级操作
目录 前言 1 Linux用户管理基础概念 1.1 Linux用户类型 1.2 用户相关配置文件 1.3 UID与GID 2 用户创建与管理 2.1 创建用户 2.2 设置用户密码 3 用户权限管理 3.1 授予sudo权限 3.2 以其他用户身份执行命令 4 用户信息查询 4.1 查看用户基本信息 4.2 查看用户所…...
POP3、IMAP、SMTP:三大邮件协议核心差异与应用场景解析
## 一、协议概述与核心功能 电子邮件系统的运行依赖三大核心协议:**POP3**(Post Office Protocol 3)、**IMAP**(Internet Message Access Protocol)和**SMTP**(Simple Mail Transfer Protocol)…...
HarmonyOS5 仓颉入门:和 ArkTs 互操作
现在一般的场景是在已有 ArkTs 库中使用仓颉,所以可以将仓颉代码封装为 ArkTs 库,提供给外部使用。 原理就是互操作宏解析被注解修饰的仓颉代码,会自动生成 ArkTs 声明文件和互操作层代码。 使用步骤: 1.在 cj 文件中ÿ…...
【Git 合并冲突解决记录:从 “refusing to merge unrelated histories“ 到批量冲突处理】
Git 合并冲突解决记录:从 “refusing to merge unrelated histories” 到批量冲突处理 前言 作为开发者,我们经常会遇到各种 Git 问题,其中最让人头疼的莫过于 fatal: refusing to merge unrelated histories 这个错误。最近在项目开发中遇…...