Java详解LeetCode 热题 100(11):LeetCode 239. 滑动窗口最大值(Sliding Window Maximum)详解

文章目录

    • 1. 题目描述
    • 2. 理解题目
    • 3. 解法一:暴力法
      • 3.1 思路
      • 3.2 Java代码实现
      • 3.3 代码详解
      • 3.4 复杂度分析
      • 3.5 适用场景
    • 4. 解法二:优先队列(最大堆)
      • 4.1 思路
      • 4.2 Java代码实现
      • 4.3 代码详解
      • 4.4 复杂度分析
      • 4.5 适用场景
    • 5. 解法三:双端队列(Deque)
      • 5.1 思路
      • 5.2 Java代码实现
      • 5.3 代码详解
      • 5.4 复杂度分析
      • 5.5 适用场景
    • 6. 解法四:动态规划法
      • 6.1 思路
      • 6.2 Java代码实现
      • 6.3 代码详解
      • 6.4 复杂度分析
      • 6.5 适用场景
    • 7. 优化与提升
      • 7.1 滑动窗口处理技巧
      • 7.2 双端队列优化
      • 7.3 处理大规模数据
    • 8. 进阶思考与变体问题
      • 8.1 滑动窗口最小值
      • 8.2 多个窗口大小
      • 8.3 实时数据流中的滑动窗口最大值
    • 9. 常见错误与优化
      • 9.1 常见错误
      • 9.2 性能优化
    • 10. 完整的 Java 解决方案
    • 11. 实际运用示例
      • 11.1 LeetCode提交结果
      • 11.2 应用场景
      • 11.3 扩展用例
    • 12. 总结与技巧
      • 12.1 解题要点
      • 12.2 学习收获
      • 12.3 面试技巧
    • 13. 参考资料

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    31 [3  -1  -3] 5  3  6  7    31  3 [-1  -3  5] 3  6  7    51  3  -1 [-3  5  3] 6  7    51  3  -1  -3 [5  3  6] 7    61  3  -1  -3  5 [3  6  7]   7

示例 2:

输入:nums = [1], k = 1
输出:[1]

示例 3:

输入:nums = [1,-1], k = 1
输出:[1,-1]

示例 4:

输入:nums = [9,11], k = 2
输出:[11]

示例 5:

输入:nums = [4,-2], k = 2
输出:[4]

提示:

  • 1 <= nums.length <= 10^5
  • -10^4 <= nums[i] <= 10^4
  • 1 <= k <= nums.length

2. 理解题目

这道题需要我们求解滑动窗口内的最大值。滑动窗口是固定大小为k的子数组,从数组左端开始,每次向右移动一个位置,直到窗口右端达到数组末尾。

关键理解:

  1. 窗口大小固定为k
  2. 窗口每次向右移动一个位置
  3. 需要返回每个窗口位置的最大值
  4. 最终结果是一个长度为n-k+1的数组,其中n是原数组长度

例如,对于示例1中的数组[1,3,-1,-3,5,3,6,7]和k=3:

  • 第一个窗口包含元素[1,3,-1],最大值是3
  • 第二个窗口包含元素[3,-1,-3],最大值是3
  • 第三个窗口包含元素[-1,-3,5],最大值是5
  • 依此类推…

最终输出:[3,3,5,5,6,7]

3. 解法一:暴力法

3.1 思路

最直接的思路是对每个窗口位置,遍历窗口内的所有元素来找出最大值。

具体步骤:

  1. 对于每个窗口位置(从0到n-k),遍历窗口内的k个元素
  2. 找出这k个元素中的最大值
  3. 将最大值添加到结果数组中

3.2 Java代码实现

public class Solution {public int[] maxSlidingWindow(int[] nums, int k) {int n = nums.length;if (n == 0 || k == 0) {return new int[0];}// 结果数组长度为 n-k+1int[] result = new int[n - k + 1];// 对每个窗口位置for (int i = 0; i <= n - k; i++) {int max = nums[i]; // 初始化为窗口内第一个元素// 遍历窗口内的其他元素for (int j = i + 1; j < i + k; j++) {max = Math.max(max, nums[j]);}result[i] = max; // 保存当前窗口的最大值}return result;}
}

3.3 代码详解

  1. 首先处理边界情况:如果数组为空或窗口大小为0,返回空数组
  2. 创建结果数组,其长度为n-k+1
  3. 外层循环遍历每个窗口的起始位置
  4. 内层循环遍历当前窗口内的元素,找出最大值
  5. 将当前窗口的最大值存入结果数组

3.4 复杂度分析

  • 时间复杂度:O(n*k),其中n是数组长度。对于每个窗口位置(共n-k+1个),我们需要O(k)时间找出窗口内的最大值。
  • 空间复杂度:O(n-k+1),即结果数组的大小。

3.5 适用场景

暴力法适用于数组长度不大且窗口大小较小的情况。当数组长度或窗口大小较大时,这种方法效率较低。

4. 解法二:优先队列(最大堆)

4.1 思路

我们可以使用优先队列(最大堆)来维护窗口中的元素,这样可以在O(log k)时间内获取窗口中的最大值。

为了处理元素移出窗口的情况,我们需要在队列中存储元素值和索引的对,这样可以判断堆顶元素是否还在当前窗口内。

具体步骤:

  1. 创建一个最大堆,存储元素值和索引的对
  2. 初始将前k个元素加入堆
  3. 对于每个窗口位置:
    • 检查堆顶元素是否在当前窗口内(通过索引判断)
    • 如果不在,弹出堆顶元素,直到找到一个在窗口内的元素
    • 将当前窗口的最大值(堆顶元素)添加到结果中
    • 将下一个元素加入堆(如果存在)

4.2 Java代码实现

import java.util.PriorityQueue;
import java.util.Comparator;public class Solution {public int[] maxSlidingWindow(int[] nums, int k) {int n = nums.length;if (n == 0 || k == 0) {return new int[0];}// 结果数组int[] result = new int[n - k + 1];// 创建最大堆,按元素值降序排列PriorityQueue<int[]> maxHeap = new PriorityQueue<>((a, b) -> b[0] - a[0] // 降序排列,最大值在堆顶);// 初始将前k个元素加入堆for (int i = 0; i < k; i++) {maxHeap.offer(new int[]{nums[i], i});}// 获取第一个窗口的最大值result[0] = maxHeap.peek()[0];// 处理后续窗口for (int i = k; i < n; i++) {// 添加当前元素到堆maxHeap.offer(new int[]{nums[i], i});// 移除不在当前窗口内的元素while (!maxHeap.isEmpty() && maxHeap.peek()[1] <= i - k) {maxHeap.poll();}// 当前窗口的最大值result[i - k + 1] = maxHeap.peek()[0];}return result;}
}

4.3 代码详解

  1. 处理边界情况:如果数组为空或窗口大小为0,返回空数组
  2. 创建结果数组,其长度为n-k+1
  3. 创建最大堆,存储元素值和索引的二元组,按元素值降序排列
  4. 初始将前k个元素加入堆,并获取第一个窗口的最大值
  5. 对于每个后续窗口:
    • 将窗口中的新元素加入堆
    • 移除不在当前窗口内的元素(即索引小于或等于i-k的元素)
    • 将堆顶元素的值(当前窗口最大值)存入结果数组

4.4 复杂度分析

  • 时间复杂度:O(n log k),其中n是数组长度,k是窗口大小。每个元素最多入堆和出堆一次,每次操作时间为O(log k)。
  • 空间复杂度:O(k),优先队列中最多有k个元素。

4.5 适用场景

优先队列法适用于窗口大小较大的情况,因为它对每个窗口的处理不需要遍历所有k个元素。但当k很小时,暴力法可能更快。

5. 解法三:双端队列(Deque)

5.1 思路

双端队列法是本题的最优解法之一。它通过维护一个单调递减的队列(存储元素索引),保证队首始终是当前窗口的最大元素索引。

关键思想:

  • 如果一个元素比它前面的元素大,那么前面的元素就永远不会成为窗口的最大值
  • 保持队列中的元素索引对应的值是单调递减的
  • 队首元素始终是当前窗口的最大值索引

具体步骤:

  1. 创建一个双端队列,存储元素索引
  2. 遍历数组:
    • 移除队列中不在当前窗口的元素(即索引小于i-k+1的元素)
    • 从队尾开始,移除所有小于当前元素的索引
    • 将当前元素的索引加入队尾
    • 如果当前位置大于等于k-1(即已形成第一个窗口),将队首元素对应的值添加到结果中

5.2 Java代码实现

import java.util.ArrayDeque;
import java.util.Deque;public class Solution {public int[] maxSlidingWindow(int[] nums, int k) {int n = nums.length;if (n == 0 || k == 0) {return new int[0];}// 结果数组int[] result = new int[n - k + 1];// 双端队列,存储元素索引Deque<Integer> deque = new ArrayDeque<>();for (int i = 0; i < n; i++) {// 移除不在当前窗口的元素if (!deque.isEmpty() && deque.peekFirst() < i - k + 1) {deque.pollFirst();}// 移除所有小于当前元素的索引,保持队列单调递减while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {deque.pollLast();}// 将当前元素索引加入队尾deque.offerLast(i);// 当窗口首次形成并开始滑动时,添加结果if (i >= k - 1) {result[i - k + 1] = nums[deque.peekFirst()];}}return result;}
}

5.3 代码详解

  1. 处理边界情况:如果数组为空或窗口大小为0,返回空数组
  2. 创建结果数组,其长度为n-k+1
  3. 创建双端队列,用于存储元素的索引
  4. 遍历数组:
    • 移除队列中不在当前窗口范围内的元素索引
    • 从队尾开始,移除所有对应值小于当前元素的索引,这样保证队列中元素的单调递减性
    • 将当前元素的索引加入队尾
    • 如果已经形成窗口(i >= k-1),则将队首元素对应的值添加到结果数组

5.4 复杂度分析

  • 时间复杂度:O(n),其中n是数组长度。每个元素最多入队和出队一次,所有操作都是O(1)时间。
  • 空间复杂度:O(k),双端队列中最多有k个元素。

5.5 适用场景

双端队列法是该问题的最优解法,尤其适用于大型数组和大窗口。由于其线性时间复杂度,在大多数情况下都优于前两种方法。

6. 解法四:动态规划法

6.1 思路

动态规划法利用了预处理技术,将数组分为大小为k的块,并预先计算每个块内的最大值。

具体步骤:

  1. 将数组分为大小为k的块
  2. 预处理两个辅助数组:
    • leftMax[i]:从块的左边界到位置i的最大值
    • rightMax[i]:从块的右边界到位置i的最大值
  3. 对于每个窗口,其最大值为max(rightMax[i], leftMax[i+k-1]),其中i是窗口的左边界

6.2 Java代码实现

public class Solution {public int[] maxSlidingWindow(int[] nums, int k) {int n = nums.length;if (n == 0 || k == 0) {return new int[0];}// 结果数组int[] result = new int[n - k + 1];// 预处理数组int[] leftMax = new int[n];int[] rightMax = new int[n];// 计算leftMaxfor (int i = 0; i < n; i++) {// 如果i是块的左边界if (i % k == 0) {leftMax[i] = nums[i];} else {leftMax[i] = Math.max(leftMax[i - 1], nums[i]);}}// 计算rightMaxfor (int i = n - 1; i >= 0; i--) {// 如果i是块的右边界,或者是数组的最后一个元素if (i % k == k - 1 || i == n - 1) {rightMax[i] = nums[i];} else {rightMax[i] = Math.max(rightMax[i + 1], nums[i]);}}// 计算每个窗口的最大值for (int i = 0; i <= n - k; i++) {// 窗口的右边界是i+k-1result[i] = Math.max(rightMax[i], leftMax[i + k - 1]);}return result;}
}

6.3 代码详解

  1. 处理边界情况
  2. 创建结果数组和两个辅助数组leftMaxrightMax
  3. 计算leftMax数组:
    • 如果i是块的左边界,leftMax[i] = nums[i]
    • 否则,leftMax[i] = max(leftMax[i-1], nums[i])
  4. 计算rightMax数组:
    • 如果i是块的右边界或数组的最后一个元素,rightMax[i] = nums[i]
    • 否则,rightMax[i] = max(rightMax[i+1], nums[i])
  5. 计算每个窗口的最大值:
    • 对于窗口[i, i+k-1],最大值为max(rightMax[i], leftMax[i+k-1])

6.4 复杂度分析

  • 时间复杂度:O(n),其中n是数组长度。预处理数组和计算结果都只需一次遍历。
  • 空间复杂度:O(n),需要两个辅助数组。

6.5 适用场景

动态规划法与双端队列法一样高效,但实现更直观。当需要处理静态数据(不会动态更新)时,这种方法尤其适用。

7. 优化与提升

7.1 滑动窗口处理技巧

在处理滑动窗口问题时,有一些常用技巧:

  1. 窗口形式的循环

    for (int right = 0; right < nums.length; right++) {// 扩展窗口右边界while (/* 需要缩小窗口的条件 */) {// 缩小窗口左边界left++;}// 计算当前窗口的结果
    }
    
  2. 双指针技术:使用左右两个指针表示窗口的边界,根据条件移动指针。

  3. 队列/堆的应用:使用适当的数据结构来高效维护窗口内的最值。

7.2 双端队列优化

上述双端队列解法可以进一步优化:

  1. 初始填充队列:先处理前k个元素,构建初始队列:

    // 填充初始队列
    for (int i = 0; i < k; i++) {while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) {deque.pollLast();}deque.offerLast(i);
    }
    result[0] = nums[deque.peekFirst()];// 处理后续元素
    for (int i = k; i < nums.length; i++) {// 常规处理
    }
    
  2. 减少不必要的检查:对于大型数组,可以考虑每k个元素清空并重建队列,避免频繁检查元素是否在窗口内。

7.3 处理大规模数据

对于非常大的数组,可以考虑以下优化:

  1. 分块处理:将数组分成多个块,分别处理后合并结果。
  2. 并行计算:利用多线程并行计算不同块的结果。
  3. 内存优化:对于动态规划解法,可以使用循环数组减少内存使用。

8. 进阶思考与变体问题

8.1 滑动窗口最小值

与本题相似,找出滑动窗口中的最小值。解法与找最大值类似,只需调整比较方向:

public int[] minSlidingWindow(int[] nums, int k) {int n = nums.length;int[] result = new int[n - k + 1];Deque<Integer> deque = new ArrayDeque<>();for (int i = 0; i < n; i++) {// 移除不在当前窗口的元素if (!deque.isEmpty() && deque.peekFirst() < i - k + 1) {deque.pollFirst();}// 保持队列单调递增while (!deque.isEmpty() && nums[deque.peekLast()] > nums[i]) {deque.pollLast();}deque.offerLast(i);if (i >= k - 1) {result[i - k + 1] = nums[deque.peekFirst()];}}return result;
}

8.2 多个窗口大小

如果需要计算多个不同大小的窗口的最大值,一个有效的方法是预处理出各种范围的最大值(稀疏表/Sparse Table):

// 构建稀疏表
int[][] sparseTable = new int[n][log2(n) + 1];
for (int i = 0; i < n; i++) {sparseTable[i][0] = nums[i];
}for (int j = 1; (1 << j) <= n; j++) {for (int i = 0; i + (1 << j) - 1 < n; i++) {sparseTable[i][j] = Math.max(sparseTable[i][j-1], sparseTable[i + (1 << (j-1))][j-1]);}
}// 查询范围[L,R]的最大值
public int queryMax(int L, int R) {int j = (int) Math.log(R - L + 1) / Math.log(2);return Math.max(sparseTable[L][j], sparseTable[R - (1 << j) + 1][j]);
}

8.3 实时数据流中的滑动窗口最大值

对于实时数据流,可以使用双端队列方法,不断添加新元素并移除过期元素:

class SlidingWindowMaximum {private Deque<Integer> deque = new ArrayDeque<>();private int[] nums;private int k;private int count = 0;public SlidingWindowMaximum(int k) {this.k = k;this.nums = new int[k];}public int add(int val) {// 计算当前元素在数组中的位置int index = count % k;count++;nums[index] = val;// 重建队列deque.clear();for (int i = 0; i < k; i++) {while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) {deque.pollLast();}deque.offerLast(i);}return nums[deque.peekFirst()];}
}

9. 常见错误与优化

9.1 常见错误

  1. 忘记移除窗口外的元素

    // 错误:没有移除窗口外的元素
    for (int i = 0; i < n; i++) {// 添加当前元素deque.offerLast(i);// 检查当前窗口最大值// ...
    }
    

    正确做法:

    for (int i = 0; i < n; i++) {// 移除窗口外的元素if (!deque.isEmpty() && deque.peekFirst() < i - k + 1) {deque.pollFirst();}// 添加当前元素// ...
    }
    
  2. 错误的队列维护

    // 错误:没有正确维护队列的单调性
    while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) {deque.pollLast();
    }
    

    这个比较条件应该是<还是<=取决于我们是否需要处理重复元素。如果队列中保留了重复的最大值,当最大值移出窗口时,可能会错误地保留这个值。

  3. 索引混淆

    // 错误:窗口索引计算错误
    result[i - k] = nums[deque.peekFirst()];
    

    正确做法:

    result[i - k + 1] = nums[deque.peekFirst()];
    

9.2 性能优化

  1. 避免频繁检查窗口边界

    // 优化前
    for (int i = 0; i < n; i++) {if (!deque.isEmpty() && deque.peekFirst() < i - k + 1) {deque.pollFirst();}// ...
    }// 优化后
    for (int i = 0; i < n; i++) {// 只有当队列非空且第一个元素肯定过期时才检查if (!deque.isEmpty() && i - deque.peekFirst() >= k) {deque.pollFirst();}// ...
    }
    
  2. 预分配足够的空间

    // 预先知道结果大小
    int[] result = new int[n - k + 1];
    Deque<Integer> deque = new ArrayDeque<>(k); // 指定初始容量
    
  3. 使用数组实现双端队列:自定义双端队列实现,避免Java内置集合类的开销:

    class ArrayDeque {private int[] array;private int front, rear;private int capacity;public ArrayDeque(int capacity) {this.capacity = capacity;array = new int[capacity];front = rear = -1;}// 实现offerLast, pollFirst, peekFirst, peekLast等方法// ...
    }
    

10. 完整的 Java 解决方案

下面是结合了各种优化的完整解法,使用双端队列实现:

import java.util.ArrayDeque;
import java.util.Deque;class Solution {public int[] maxSlidingWindow(int[] nums, int k) {if (nums == null || nums.length == 0 || k <= 0) {return new int[0];}int n = nums.length;int[] result = new int[n - k + 1];Deque<Integer> deque = new ArrayDeque<>(k);// 处理前k个元素,建立初始单调队列for (int i = 0; i < k; i++) {// 保持队列单调递减while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) {deque.pollLast();}deque.offerLast(i);}// 第一个窗口的最大值result[0] = nums[deque.peekFirst()];// 处理剩余元素for (int i = k; i < n; i++) {// 移除不在当前窗口的元素if (!deque.isEmpty() && deque.peekFirst() <= i - k) {deque.pollFirst();}// 保持队列单调递减while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) {deque.pollLast();}deque.offerLast(i);// 当前窗口的最大值result[i - k + 1] = nums[deque.peekFirst()];}return result;}
}

11. 实际运用示例

11.1 LeetCode提交结果

双端队列解法在LeetCode上提交的结果通常如下:

  • 执行用时:约 15-30 ms(击败约 90-95% 的 Java 提交)
  • 内存消耗:约 50-60 MB(击败约 80-85% 的 Java 提交)

11.2 应用场景

滑动窗口最大值问题在实际编程中有很多应用场景,例如:

  • 股票市场中计算n天内的最高价格
  • 网络流量监控中检测特定时间窗口内的峰值流量
  • 图像处理中的最大值滤波器
  • 数据流处理中的实时数据分析

11.3 扩展用例

public class SlidingWindowMaximumApplication {public static void main(String[] args) {Solution solution = new Solution();// 基本测试用例test(solution, new int[]{1, 3, -1, -3, 5, 3, 6, 7}, 3);// 边界测试用例test(solution, new int[]{1}, 1);test(solution, new int[]{1, -1}, 1);// 窗口大小等于数组长度test(solution, new int[]{1, 3, 5, 7}, 4);// 大型测试用例int[] largeArray = new int[10000];for (int i = 0; i < 10000; i++) {largeArray[i] = (int)(Math.random() * 10000);}long startTime = System.currentTimeMillis();solution.maxSlidingWindow(largeArray, 100);long endTime = System.currentTimeMillis();System.out.println("大型测试用例耗时: " + (endTime - startTime) + "ms");}private static void test(Solution solution, int[] nums, int k) {int[] result = solution.maxSlidingWindow(nums, k);System.out.print("数组: ");printArray(nums);System.out.println("窗口大小: " + k);System.out.print("结果: ");printArray(result);System.out.println();}private static void printArray(int[] arr) {System.out.print("[");for (int i = 0; i < arr.length; i++) {System.out.print(arr[i]);if (i < arr.length - 1) {System.out.print(", ");}}System.out.println("]");}
}

12. 总结与技巧

12.1 解题要点

  1. 理解滑动窗口概念:理解窗口的移动过程和窗口内元素的更新方式。
  2. 选择合适的数据结构:根据问题特点选择合适的数据结构,如双端队列、优先队列等。
  3. 单调队列技巧:掌握维护单调队列的方法,这是解决滑动窗口最值问题的关键。
  4. 处理边界情况:注意窗口初始形成和结束时的特殊处理。
  5. 优化时间复杂度:尽量避免重复计算,争取O(n)时间复杂度。

12.2 学习收获

通过学习这道题,你可以掌握:

  • 滑动窗口算法的基本思想
  • 双端队列的应用
  • 单调队列的维护方法
  • 优化算法的常用技巧
  • 处理序列和窗口问题的通用方法

12.3 面试技巧

在面试中遇到类似问题时:

  1. 先分析最简单的解法(如暴力法)
  2. 分析其时间和空间复杂度的瓶颈
  3. 引入双端队列或堆等优化方法
  4. 讨论维护窗口最大值的策略(单调队列)
  5. 处理各种边界情况

13. 参考资料

  • LeetCode 239. 滑动窗口最大值
  • 单调队列详解
  • 动态规划方法讲解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/79887.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

org.apache.poi——将 office的各种类型文件(word等文件类型)转为 pdf

org.apache.poi——将 office的各种类型文件&#xff08;word等文件类型&#xff09;转为 pdf 简介使用方法word转pdf 使用示例word转pdf 简介 使用方法 word转pdf Maven坐标为 <dependency><groupId>com.documents4j</groupId><artifactId>documen…

二叉树与优先级队列

1.树 树是由n个数据构成的非线性结构&#xff0c;它是根朝上&#xff0c;叶朝下。 注意&#xff1a;树形结构之中&#xff0c;子树之间不能连接&#xff0c;不然就不构成树形结构 1.子树之间没有交集 2.除了根节点以外&#xff0c;每一个节点有且只有一个父亲节点 3.一个n个…

如何进行室内VR全景拍摄?

如何进行室内VR全景拍摄&#xff1f; 室内VR全景拍摄作为先进的视觉技术&#xff0c;能够为用户提供沉浸式的空间体验。本文介绍如何进行室内VR全景拍摄&#xff0c;并阐述众趣科技在这一领域的技术支持和服务优势。 室内VR全景拍摄基础 1. 室内VR全景拍摄概述 室内VR全景拍…

如何通过代理 IP 实现异地直播推流

在直播行业日益火爆的今天&#xff0c;许多主播希望突破地域限制&#xff0c;实现异地直播推流&#xff0c;以获得更广泛的观众群体和更好的直播效果。代理 IP 作为一种有效的网络工具&#xff0c;能够帮助主播轻松达成这一目标。本文将详细介绍如何通过代理 IP 实现异地直播推…

随机变量数字特征

主要介绍一维随机变量期望和方差、二维随机变量期望和方差、以及协方差相关公式&#xff0c;及推导。 一维随机变量 以一个抛硬币的场景作为例子&#xff0c;如下&#xff1a; 抛掷两枚均匀硬币&#xff0c;如果两枚都是正面向上&#xff0c;则赢得2元&#xff0c;否则就输掉…

上传图片后,如何调用API进行商品搜索?

以下是一个完整的示例&#xff0c;展示如何在上传图片后调用淘宝按图搜索商品&#xff08;拍立淘&#xff09;API进行商品搜索&#xff1a; 1. 准备工作 注册账号并获取API密钥&#xff1a;在淘宝开放平台注册账号&#xff0c;创建应用&#xff0c;获取app_key和app_secret。 …

Android 数据持久化之 Room 数据库存储

一、简介 Room 是 Google 推出的 Android 持久层框架,建立在 SQLite 之上,提供了一个抽象层,简化了数据库操作。它通过注解和编译时检查来确保数据操作的正确性。 Room 主要由以下三个组件组成: Entity(实体):定义封装实际数据的实体类,每个实体类对应数据库中的一个…

react中的用法——setDisabled dva dispatch effects

setDisabled 在react中&#xff0c;setDisabled通常是指通过状态管理来控制某个组件&#xff08;如按钮、输入框等&#xff09;的禁用状态。虽然react本身没有内置的setDisabled方法&#xff0c;但你可以使用useState钩子来实现类似的功能。以下是一个简单的示例&#xff0c;展…

html css js网页制作成品——HTML+CSS珠海网页设计网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…

C语言复习笔记--自定义类型

今天我们来复习一下自定义类型.自定义类型大概分为结构体,枚举,联合体,数组这几种.数组在之前就介绍过.今天我们来看下其他三种. 结构体 首先来看结构体. 结构体类型的声明 之前在操作符的地方简单认识过结构体.下面我们回顾一下. 结构体回顾 结构是⼀些值的集合&#xff0c;这…

python jupyter notebook

什么是Jupyter Notebook Jupyter Notebook是一个开源的Web应用程序&#xff0c;允许用户创建和共享包含实时代码、方程、可视化和解释性文本的文档。它最初由IPython团队开发&#xff0c;现在已经成为一个独立的项目&#xff0c;并广泛用于数据清理和转换、数值模拟、统计建模…

Linux——https基础理论

1. 初步认识https协议 • 属于应用层 • 相较于http协议&#xff0c;https在应用层多了一层加密层&#xff0c;为了保证数据安全 • 简单理解&#xff1a;https就是对http的加密和解密 2. 中间人攻击 • 数据在传输过程中&#xff0c;遭第三方篡改。 3. 加密方式 • 对称加密&a…

在 C++ 中对类型进行排序

0.前言 在 C 中&#xff0c;我编写了一个 tuple-like 模板&#xff0c;这个模板能容纳任意多且可重复的类型&#xff1a; template<typename... Ts> struct TypeList {};// usage: using List1 TypeList<int, double, char, double>; using List2 TypeList<…

Unity-Socket通信实例详解

今天我们来讲解socket通信。 首先我们需要知道什么是socket通信&#xff1a; Socket本质上就是一个个进程之间网络通信的基础&#xff0c;每一个Socket由IP端口组成&#xff0c;熟悉计网的同学应该知道IP主要是应用于IP协议而端口主要应用于TCP协议&#xff0c;这也证明了Sock…

使用Go语言对接全球股票数据源API实践指南

使用Go语言对接全球股票数据API实践指南 概述 本文介绍如何通过Go语言对接支持多国股票数据的API服务。我们将基于提供的API文档&#xff0c;实现包括市场行情、K线数据、实时推送等核心功能的对接。 一、准备工作 1. 获取API Key 联系服务提供商获取访问密钥&#xff08;替…

LeetCode 热题 100 17. 电话号码的字母组合

LeetCode 热题 100 | 17. 电话号码的字母组合 大家好&#xff0c;今天我们来解决一道经典的算法题——电话号码的字母组合。这道题在 LeetCode 上被标记为中等难度&#xff0c;要求给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。下面我将详细讲解解…

OpenCV计算机视觉实战(3)——计算机图像处理基础

OpenCV计算机视觉实战&#xff08;3&#xff09;——计算机图像处理基础 0. 前言1. 像素和图像表示1.1 像素 2. 色彩空间2.1 原色2.2 色彩空间2.3 像素和色彩空间 3. 文件类型3.1 图像文件类型3.2 视频文件3.3 图像与视频 4. 计算机图像编程简史5. OpenCV 概述小结系列链接 0. …

Vite 的工作流程

Vite 的工作流程基于其创新的 “预构建 按需加载” 机制&#xff0c;通过利用现代浏览器对原生 ES 模块的支持&#xff0c;显著提升了开发效率和构建速度。以下是其核心工作流程的详细分析&#xff1a; 一、开发环境工作流程 1. 启动开发服务器 冷启动&#xff1a;通过 npm …

线性DP(动态规划)

线性DP的概念&#xff08;视频&#xff09; 学习线性DP之前&#xff0c;请确保已经对递推有所了解。 一、概念 1、动态规划 不要去看网上的各种概念&#xff0c;什么无后效性&#xff0c;什么空间换时间&#xff0c;会越看越晕。从做题的角度去理解就好了&#xff0c;动态规划…

MySQL中sql_mode的设置

■ 57版本原来配置 show variables like %sql_mode%; STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION ■ 修改配置文件 注释掉sql_mode&#xff0c;并重启&#xff0c;查看57版本的默认设置 ONL…