当前位置: 首页 > news >正文

简单多状态 dp 问题(典型算法思想)—— OJ例题算法解析思路

目录

一、面试题 17.16. 按摩师 - 力扣(LeetCode)

算法代码:

代码思路解析:

问题分析:

动态规划定义:

状态转移方程:

初始化:

填表:

返回值:

优化空间复杂度:

二、213. 打家劫舍 II - 力扣(LeetCode) 

算法代码: 

代码思路解析:

1. 主函数 rob:

2. 辅助函数 rob1:

3. 状态转移方程:

4. 初始化:

5. 填表:

6. 返回结果:

优化空间复杂度:

总结:

三、740. 删除并获得点数 - 力扣(LeetCode) 

算法代码: 

代码思路解析:

1. 预处理:

2. 转化为“打家劫舍”问题:

3. 动态规划定义:

4. 状态转移方程:

5. 初始化:

6. 填表:

7. 返回结果:

优化空间复杂度:

总结:

四、 LCR 091. 粉刷房子 - 力扣(LeetCode)

方法一:算法代码(dp从1开始,costs从0开始)

索引对齐问题:

代码思路解析:

1. 问题分析:

2. 动态规划定义:

3. 状态转移方程:

4. 初始化:

5. 填表:

6. 返回结果:

优化空间复杂度:

总结:

方法二:算法代码(dp从0开始,costs也从0开始)

1. 从 0 开始的动态规划表:

2. 状态转移方程:

3. 初始化:

4. 为什么可以从 0 开始?

5. 举例说明:

6. 总结:

五、309. 买卖股票的最佳时机含冷冻期 - 力扣(LeetCode) 

算法代码: 

代码思路解析:

1. 问题分析:

2. 动态规划定义:

3. 状态转移方程:

4. 初始化:

5. 填表:

6. 返回结果:

优化空间复杂度:

总结:

六、 714. 买卖股票的最佳时机含手续费 - 力扣(LeetCode)

算法代码:

代码思路解析:

1. 问题分析:

2. 动态规划定义:

3. 状态转移方程:

4. 初始化:

5. 填表:

6. 返回结果:

优化空间复杂度:

总结:

七、123. 买卖股票的最佳时机 III - 力扣(LeetCode) 

算法代码:

代码思路解析:

1. 问题分析:

2. 动态规划定义:

3. 状态转移方程:

4. 初始化:

5. 填表:

6. 返回结果:

优化空间复杂度:

总结:

八、 188. 买卖股票的最佳时机 IV - 力扣(LeetCode)

算法代码:

代码思路解析:

1. 问题分析:

2. 动态规划定义:

3. 状态转移方程:

4. 初始化:

5. 填表:

6. 返回结果:

优化空间复杂度:

总结:

 


一、面试题 17.16. 按摩师 - 力扣(LeetCode)

算法代码:

class Solution {
public:int massage(vector<int>& nums) {int n = nums.size();if (n == 0)return 0; // 处理边界条件// 定义两个状态数组vector<int> f(n); // f[i] 表示选择第 i 个预约时的最大价值vector<int> g(n); // g[i] 表示不选择第 i 个预约时的最大价值// 初始化f[0] = nums[0];g[0] = 0;// 填表for (int i = 1; i < n; i++) {f[i] = g[i - 1] + nums[i]; // 选择第 i 个预约g[i] = max(f[i - 1], g[i - 1]); // 不选择第 i 个预约}// 返回最大值return max(f[n - 1], g[n - 1]);}
};

        这个代码实现了一个动态规划问题,通常被称为“按摩师问题”或“打家劫舍问题”。问题的核心是:给定一个数组 nums,表示每个预约的时长或价值,要求在不连续选择相邻元素的情况下,找到最大价值的组合。

代码思路解析:

  1. 问题分析

    • 每个元素 nums[i] 表示第 i 个预约的价值。

    • 不能选择相邻的预约,即如果选择了 nums[i],就不能选择 nums[i-1] 和 nums[i+1]

    • 目标是找到一种选择方式,使得总价值最大。

  2. 动态规划定义

    • 定义两个状态数组 f 和 g

      • f[i] 表示选择第 i 个预约时的最大价值。

      • g[i] 表示不选择第 i 个预约时的最大价值。

    • 通过这两个状态数组,可以递推地计算出每一步的最优解。

  3. 状态转移方程

    • 如果选择第 i 个预约,那么前一个预约不能选择,因此 f[i] = g[i-1] + nums[i]

    • 如果不选择第 i 个预约,那么前一个预约可以选择或不选择,取两者中的最大值,因此 g[i] = max(f[i-1], g[i-1])

  4. 初始化

    • f[0] = nums[0]:如果只有一个预约,那么选择它的价值就是 nums[0]

    • g[0] = 0:如果不选择第一个预约,那么价值为 0。

  5. 填表

    • 从 i = 1 开始,逐步计算 f[i] 和 g[i],直到 i = n-1

  6. 返回值

    • 最终的结果是 max(f[n-1], g[n-1]),即选择或不选择最后一个预约的最大价值。

优化空间复杂度:

当前的空间复杂度是 O(n),可以通过滚动数组的方式优化到 O(1)

class Solution {
public:int massage(vector<int>& nums) {int n = nums.size();if (n == 0)return 0;int f = nums[0]; // 选择当前预约的最大价值int g = 0;       // 不选择当前预约的最大价值for (int i = 1; i < n; i++) {int new_f = g + nums[i]; // 选择当前预约int new_g = max(f, g);   // 不选择当前预约f = new_f;g = new_g;}return max(f, g);}
};

这个优化版本只使用了两个变量 f 和 g,空间复杂度降低到了 O(1)

二、213. 打家劫舍 II - 力扣(LeetCode) 

算法代码: 

class Solution {
public:int rob(vector<int>& nums) {int n = nums.size();if (n == 0) return 0;if (n == 1) return nums[0]; // 边界条件处理// 两种情况下的最大值return max(nums[0] + rob1(nums, 2, n - 2), rob1(nums, 1, n - 1));}int rob1(vector<int>& nums, int left, int right) {if (left > right) return 0; // 边界条件处理int n = nums.size();vector<int> f(n); // f[i] 表示偷第 i 个房屋时的最大价值vector<int> g(n); // g[i] 表示不偷第 i 个房屋时的最大价值// 初始化f[left] = nums[left];g[left] = 0;// 填表for (int i = left + 1; i <= right; i++) {f[i] = g[i - 1] + nums[i]; // 偷第 i 个房屋g[i] = max(f[i - 1], g[i - 1]); // 不偷第 i 个房屋}// 返回结果return max(f[right], g[right]);}
};

        这个代码实现了一个动态规划问题,通常被称为“环形打家劫舍问题”。与普通的打家劫舍问题不同,这里的房屋是环形排列的,即第一个房屋和最后一个房屋是相邻的。因此,我们需要考虑两种情况:

  1. 偷第一个房屋,但不能偷最后一个房屋

  2. 不偷第一个房屋,可以偷最后一个房屋

最终的结果是这两种情况的最大值。

代码思路解析:

1. 主函数 rob

  • 首先检查数组的长度 n

  • 调用辅助函数 rob1 分别计算两种情况的最大值:

    • 情况 1:偷第一个房屋,但不能偷最后一个房屋。即 nums[0] + rob1(nums, 2, n - 2)

    • 情况 2:不偷第一个房屋,可以偷最后一个房屋。即 rob1(nums, 1, n - 1)

  • 返回两种情况的最大值。

2. 辅助函数 rob1

  • 这个函数用于计算在给定区间 [left, right] 内偷取房屋的最大价值。

  • 使用动态规划的思想,定义两个状态数组 f 和 g

    • f[i] 表示偷第 i 个房屋时的最大价值。

    • g[i] 表示不偷第 i 个房屋时的最大价值。

  • 通过状态转移方程逐步计算每个位置的最优解。

3. 状态转移方程

  • 如果偷第 i 个房屋,那么前一个房屋不能偷,因此 f[i] = g[i - 1] + nums[i]

  • 如果不偷第 i 个房屋,那么前一个房屋可以偷或不偷,取两者中的最大值,因此 g[i] = max(f[i - 1], g[i - 1])

4. 初始化

  • f[left] = nums[left]:如果从 left 开始偷,那么偷第一个房屋的价值就是 nums[left]

  • g[left] = 0:如果不偷第一个房屋,那么价值为 0。

5. 填表

  • 从 left + 1 开始,逐步计算 f[i] 和 g[i],直到 i = right

6. 返回结果

  • 最终的结果是 max(f[right], g[right]),即偷或不偷最后一个房屋的最大价值。

优化空间复杂度:

当前的空间复杂度是 O(n),可以通过滚动数组的方式优化到 O(1)

class Solution {
public:int rob(vector<int>& nums) {int n = nums.size();if (n == 0) return 0;if (n == 1) return nums[0]; // 边界条件处理// 两种情况下的最大值return max(nums[0] + rob1(nums, 2, n - 2), rob1(nums, 1, n - 1));}int rob1(vector<int>& nums, int left, int right) {if (left > right) return 0; // 边界条件处理int f = nums[left]; // 偷当前房屋的最大价值int g = 0;          // 不偷当前房屋的最大价值for (int i = left + 1; i <= right; i++) {int new_f = g + nums[i]; // 偷当前房屋int new_g = max(f, g);   // 不偷当前房屋f = new_f;g = new_g;}return max(f, g);}
};

总结:

  • 主函数 rob 通过调用辅助函数 rob1 分别计算两种情况的最大值。

  • 辅助函数 rob1 使用动态规划的思想,通过状态转移方程计算区间 [left, right] 内的最大价值。

  • 通过滚动数组优化,空间复杂度从 O(n) 降低到 O(1)

三、740. 删除并获得点数 - 力扣(LeetCode) 

算法代码: 

class Solution {
public:int deleteAndEarn(vector<int>& nums) {const int N = 10001;// 1. 预处理int arr[N] = {0};for (auto x : nums)arr[x] += x;// 2. 在 arr 数组上,做一次“打家劫舍”问题// 创建 dp 表vector<int> f(N); // f[i] 表示选择第 i 个元素时的最大点数vector<int> g(N); // g[i] 表示不选择第 i 个元素时的最大点数// 填表for (int i = 1; i < N; i++) {f[i] = g[i - 1] + arr[i]; // 选择第 i 个元素g[i] = max(f[i - 1], g[i - 1]); // 不选择第 i 个元素}// 返回结果return max(f[N - 1], g[N - 1]);}
};

        这个代码实现了一个动态规划问题,通常被称为“删除并获得点数”问题。问题的核心是:给定一个整数数组 nums,你可以通过删除一个元素 nums[i] 来获得 nums[i] 的点数,但同时必须删除所有等于 nums[i] - 1 和 nums[i] + 1 的元素。目标是最大化获得的点数。

代码思路解析:

1. 预处理

  • 由于数组中的元素可能很大(最大为 10000),我们使用一个大小为 10001 的数组 arr 来统计每个数字的总点数。

  • 遍历 nums,将每个数字 x 的点数累加到 arr[x] 中。例如,如果 nums = [2, 2, 3, 3, 3],那么 arr[2] = 4arr[3] = 9

2. 转化为“打家劫舍”问题

  • 经过预处理后,问题转化为在 arr 数组上解决“打家劫舍”问题:

    • 不能选择相邻的元素(因为选择 arr[i] 意味着不能选择 arr[i-1] 和 arr[i+1])。

    • 目标是最大化选择的元素的总和。

3. 动态规划定义

  • 定义两个状态数组 f 和 g

    • f[i] 表示选择第 i 个元素时的最大点数。

    • g[i] 表示不选择第 i 个元素时的最大点数。

  • 通过这两个状态数组,可以递推地计算出每一步的最优解。

4. 状态转移方程

  • 如果选择第 i 个元素,那么前一个元素不能选择,因此 f[i] = g[i - 1] + arr[i]

  • 如果不选择第 i 个元素,那么前一个元素可以选择或不选择,取两者中的最大值,因此 g[i] = max(f[i - 1], g[i - 1])

5. 初始化

  • f[0] = 0 和 g[0] = 0,因为没有元素时点数为 0。

6. 填表

  • 从 i = 1 开始,逐步计算 f[i] 和 g[i],直到 i = N - 1

7. 返回结果

  • 最终的结果是 max(f[N - 1], g[N - 1]),即选择或不选择最后一个元素的最大点数。

优化空间复杂度:

当前的空间复杂度是 O(N),其中 N = 10001。可以通过滚动数组的方式优化到 O(1)

class Solution {
public:int deleteAndEarn(vector<int>& nums) {const int N = 10001;// 1. 预处理int arr[N] = {0};for (auto x : nums)arr[x] += x;// 2. 在 arr 数组上,做一次“打家劫舍”问题int f = 0; // 选择当前元素的最大点数int g = 0; // 不选择当前元素的最大点数for (int i = 1; i < N; i++) {int new_f = g + arr[i]; // 选择当前元素int new_g = max(f, g);  // 不选择当前元素f = new_f;g = new_g;}// 返回结果return max(f, g);}
};

总结:

  • 通过预处理将问题转化为“打家劫舍”问题。

  • 使用动态规划的思想,通过状态转移方程计算最大点数。

  • 通过滚动数组优化,空间复杂度从 O(N) 降低到 O(1)

四、 LCR 091. 粉刷房子 - 力扣(LeetCode)

方法一:算法代码(dp从1开始,costs从0开始)

class Solution {
public:int minCost(vector<vector<int>>& costs) {int n = costs.size();// dp[i][j] 表示将第 i 个房子粉刷成第 j 种颜色时的最小总成本vector<vector<int>> dp(n + 1, vector<int>(3, 0));for (int i = 1; i <= n; i++) {// 选择颜色 0dp[i][0] = min(dp[i - 1][1], dp[i - 1][2]) + costs[i - 1][0];// 选择颜色 1dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + costs[i - 1][1];// 选择颜色 2dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]) + costs[i - 1][2];}// 返回最后一个房子选择三种颜色中的最小总成本return min(dp[n][0], min(dp[n][1], dp[n][2]));}
};

索引对齐问题

  • 动态规划表 dp 的索引从 1 开始:

    • dp[i][j] 表示第 i 个房子粉刷成第 j 种颜色的最小成本。

    • i 的范围是 1 到 n,表示第 1 个房子到第 n 个房子。

  • 输入数组 costs 的索引从 0 开始:

    • costs[k][j] 表示第 k 个房子粉刷成第 j 种颜色的成本。

    • k 的范围是 0 到 n-1,表示第 1 个房子到第 n 个房子。

因此,dp 表的第 i 个房子对应 costs 的第 i-1 个房子。

        这个代码实现了一个动态规划问题,通常被称为“粉刷房子”问题。问题的核心是:给定一个 n x 3 的二维数组 costs,其中 costs[i][j] 表示将第 i 个房子粉刷成第 j 种颜色的成本。要求相邻的房子不能粉刷成相同的颜色,求最小总成本。

代码思路解析:

1. 问题分析

  • 每个房子有三种颜色可选(假设为红、蓝、绿)。

  • 相邻的房子不能选择相同的颜色。

  • 目标是找到一种粉刷方案,使得总成本最小。

2. 动态规划定义

  • 定义 dp[i][j] 表示将第 i 个房子粉刷成第 j 种颜色时的最小总成本。

  • j 的取值范围是 012,分别对应三种颜色。

3. 状态转移方程

  • 对于第 i 个房子,如果选择颜色 0,那么第 i-1 个房子只能选择颜色 1 或 2。因此:

    dp[i][0] = min(dp[i-1][1], dp[i-1][2]) + costs[i-1][0];
  • 如果选择颜色 1,那么第 i-1 个房子只能选择颜色 0 或 2。因此:

    dp[i][1] = min(dp[i-1][0], dp[i-1][2]) + costs[i-1][1];
  • 如果选择颜色 2,那么第 i-1 个房子只能选择颜色 0 或 1。因此:

    dp[i][2] = min(dp[i-1][0], dp[i-1][1]) + costs[i-1][2];

4. 初始化

  • dp[0][0] = dp[0][1] = dp[0][2] = 0,表示没有房子时的成本为 0。

5. 填表

  • 从 i = 1 开始,逐步计算 dp[i][0]dp[i][1] 和 dp[i][2],直到 i = n

6. 返回结果

  • 最终的结果是 min(dp[n][0], dp[n][1], dp[n][2]),即最后一个房子选择三种颜色中的最小总成本。

优化空间复杂度:

当前的空间复杂度是 O(n),可以通过滚动数组的方式优化到 O(1)

class Solution {
public:int minCost(vector<vector<int>>& costs) {int n = costs.size();// 使用滚动数组优化空间复杂度int dp0 = 0, dp1 = 0, dp2 = 0; // 分别表示选择颜色 0、1、2 的最小成本for (int i = 1; i <= n; i++) {int new_dp0 = min(dp1, dp2) + costs[i - 1][0]; // 选择颜色 0int new_dp1 = min(dp0, dp2) + costs[i - 1][1]; // 选择颜色 1int new_dp2 = min(dp0, dp1) + costs[i - 1][2]; // 选择颜色 2dp0 = new_dp0;dp1 = new_dp1;dp2 = new_dp2;}// 返回最后一个房子选择三种颜色中的最小总成本return min(dp0, min(dp1, dp2));}
};

总结:

  • 使用动态规划的思想,通过状态转移方程计算每个房子选择不同颜色的最小成本。

  • 通过滚动数组优化,空间复杂度从 O(n) 降低到 O(1)

  • 最终结果是最后一个房子选择三种颜色中的最小总成本。

方法二:算法代码(dp从0开始,costs也从0开始)

class Solution {
public:int minCost(vector<vector<int>>& costs) {int n = costs.size();if (n == 0) return 0; // 边界条件处理// dp[i][j] 表示将第 i 个房子粉刷成第 j 种颜色时的最小总成本vector<vector<int>> dp(n, vector<int>(3));// 初始化第 0 个房子dp[0][0] = costs[0][0];dp[0][1] = costs[0][1];dp[0][2] = costs[0][2];// 填表for (int i = 1; i < n; i++) {dp[i][0] = min(dp[i - 1][1], dp[i - 1][2]) + costs[i][0]; // 选择颜色 0dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + costs[i][1]; // 选择颜色 1dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]) + costs[i][2]; // 选择颜色 2}// 返回最后一个房子选择三种颜色中的最小总成本return min(dp[n - 1][0], min(dp[n - 1][1], dp[n - 1][2]));}
};

1. 从 0 开始的动态规划表

  • dp[i][j] 表示第 i 个房子(索引从 0 开始)粉刷成第 j 种颜色的最小成本。

  • 输入数组 costs 的索引也是从 0 开始,因此 dp[i][j] 直接对应 costs[i][j]


2. 状态转移方程

  • 对于第 i 个房子(i >= 1):

    • 如果选择颜色 0,则前一个房子不能选择颜色 0

      dp[i][0] = min(dp[i-1][1], dp[i-1][2]) + costs[i][0];
    • 如果选择颜色 1,则前一个房子不能选择颜色 1

      dp[i][1] = min(dp[i-1][0], dp[i-1][2]) + costs[i][1];
    • 如果选择颜色 2,则前一个房子不能选择颜色 2

      dp[i][2] = min(dp[i-1][0], dp[i-1][1]) + costs[i][2];

3. 初始化

  • 对于第 0 个房子(i = 0):

    • dp[0][0] = costs[0][0]:选择颜色 0 的成本。

    • dp[0][1] = costs[0][1]:选择颜色 1 的成本。

    • dp[0][2] = costs[0][2]:选择颜色 2 的成本。


4. 为什么可以从 0 开始?

  • 从 0 开始的设计更符合数组的索引习惯,避免了 i - 1 的偏移。

  • 初始化时直接使用 costs[0][j],逻辑更直观。

  • 动态规划表的索引与输入数组的索引完全一致,减少了出错的可能性。


5. 举例说明

假设输入 costs = [[17, 2, 17], [16, 16, 5], [14, 3, 19]],表示有 3 个房子:

  • costs[0] = [17, 2, 17]:第 0 个房子的三种颜色成本。

  • costs[1] = [16, 16, 5]:第 1 个房子的三种颜色成本。

  • costs[2] = [14, 3, 19]:第 2 个房子的三种颜色成本。

动态规划表的计算过程:

房子 (i)dp[i][0] (颜色 0)dp[i][1] (颜色 1)dp[i][2] (颜色 2)
017217
118 (2 + 16)33 (17 + 16)7 (2 + 5)
210 (7 + 3)21 (18 + 3)26 (18 + 19)

最终结果是 min(dp[2][0], dp[2][1], dp[2][2]) = min(10, 21, 26) = 10


6. 总结

  • 动态规划表可以从 0 开始,只要正确处理索引对齐问题即可。

  • 从 0 开始的设计更直观,避免了 i - 1 的偏移,逻辑更清晰。

  • 两种实现方式(从 1 开始或从 0 开始)都是正确的,选择哪种方式取决于个人习惯和代码风格。

 

五、309. 买卖股票的最佳时机含冷冻期 - 力扣(LeetCode) 

算法代码: 

class Solution {
public:int maxProfit(vector<int>& prices) {int n = prices.size();if (n == 0) return 0; // 边界条件处理// dp[i][j] 表示第 i 天结束时处于状态 j 的最大利润vector<vector<int>> dp(n, vector<int>(3));// 初始化dp[0][0] = -prices[0]; // 第 0 天买入股票dp[0][1] = 0;          // 第 0 天不可能处于冷冻期dp[0][2] = 0;          // 第 0 天不持有股票且不处于冷冻期// 填表for (int i = 1; i < n; i++) {dp[i][0] = max(dp[i - 1][0], dp[i - 1][2] - prices[i]); // 持有股票dp[i][1] = dp[i - 1][0] + prices[i];                    // 不持有股票且处于冷冻期dp[i][2] = max(dp[i - 1][2], dp[i - 1][1]);            // 不持有股票且不处于冷冻期}// 返回结果return max(dp[n - 1][1], dp[n - 1][2]);}
};

        这个代码实现了一个动态规划问题,通常被称为“股票买卖问题(含冷冻期)”。问题的核心是:给定一个股票价格数组 prices,你可以进行多次交易,但每次卖出股票后需要有一天的冷冻期(即不能立即买入)。目标是最大化利润。

代码思路解析:

1. 问题分析

  • 每天有三种状态:

    1. 持有股票dp[i][0]):表示第 i 天结束时持有股票的最大利润。

    2. 不持有股票且处于冷冻期dp[i][1]):表示第 i 天结束时没有股票,且处于冷冻期的最大利润。

    3. 不持有股票且不处于冷冻期dp[i][2]):表示第 i 天结束时没有股票,且不处于冷冻期的最大利润。

  • 目标是找到最后一天的最大利润。

2. 动态规划定义

  • 定义 dp[i][j] 表示第 i 天结束时处于状态 j 的最大利润。

  • j 的取值范围是 012,分别对应上述三种状态。

3. 状态转移方程

  • 持有股票dp[i][0]):

    • 可能是前一天就持有股票,即 dp[i-1][0]

    • 也可能是今天买入股票,那么前一天必须是不持有股票且不处于冷冻期,即 dp[i-1][2] - prices[i]

    • 取两者的最大值:

      dp[i][0] = max(dp[i-1][0], dp[i-1][2] - prices[i]);
  • 不持有股票且处于冷冻期dp[i][1]):

    • 只有一种可能:今天卖出了股票,即前一天持有股票并卖出,即 dp[i-1][0] + prices[i]

    • 因此:

      dp[i][1] = dp[i-1][0] + prices[i];
  • 不持有股票且不处于冷冻期dp[i][2]):

    • 可能是前一天就不持有股票且不处于冷冻期,即 dp[i-1][2]

    • 也可能是前一天处于冷冻期,即 dp[i-1][1]

    • 取两者的最大值:

      dp[i][2] = max(dp[i-1][2], dp[i-1][1]);

4. 初始化

  • 第 0 天(初始状态):

    • dp[0][0] = -prices[0]:第 0 天买入股票,利润为 -prices[0]

    • dp[0][1] = 0:第 0 天不可能处于冷冻期。

    • dp[0][2] = 0:第 0 天不持有股票且不处于冷冻期。

5. 填表

  • 从 i = 1 开始,逐步计算 dp[i][0]dp[i][1] 和 dp[i][2],直到 i = n-1

6. 返回结果

  • 最终的结果是 max(dp[n-1][1], dp[n-1][2]),即最后一天不持有股票的最大利润(可能是冷冻期或非冷冻期)。

优化空间复杂度:

当前的空间复杂度是 O(n),可以通过滚动数组的方式优化到 O(1)

class Solution {
public:int maxProfit(vector<int>& prices) {int n = prices.size();if (n == 0) return 0; // 边界条件处理// 使用滚动数组优化空间复杂度int dp0 = -prices[0]; // 持有股票int dp1 = 0;          // 不持有股票且处于冷冻期int dp2 = 0;          // 不持有股票且不处于冷冻期for (int i = 1; i < n; i++) {int new_dp0 = max(dp0, dp2 - prices[i]); // 持有股票int new_dp1 = dp0 + prices[i];          // 不持有股票且处于冷冻期int new_dp2 = max(dp2, dp1);            // 不持有股票且不处于冷冻期dp0 = new_dp0;dp1 = new_dp1;dp2 = new_dp2;}// 返回结果return max(dp1, dp2);}
};

总结:

  • 使用动态规划的思想,通过状态转移方程计算每天的最大利润。

  • 通过滚动数组优化,空间复杂度从 O(n) 降低到 O(1)

  • 最终结果是最后一天不持有股票的最大利润(可能是冷冻期或非冷冻期)。

六、 714. 买卖股票的最佳时机含手续费 - 力扣(LeetCode)

算法代码:

class Solution {
public:int maxProfit(vector<int>& prices, int fee) {int n = prices.size();if (n == 0) return 0; // 边界条件处理// f[i] 表示第 i 天结束时持有股票的最大利润// g[i] 表示第 i 天结束时没有股票的最大利润vector<int> f(n);vector<int> g(n);// 初始化f[0] = -prices[0]; // 第 0 天买入股票g[0] = 0;          // 第 0 天不持有股票// 填表for (int i = 1; i < n; i++) {f[i] = max(f[i - 1], g[i - 1] - prices[i]); // 持有股票g[i] = max(g[i - 1], f[i - 1] + prices[i] - fee); // 不持有股票}// 返回结果return g[n - 1];}
};

        这个代码实现了一个动态规划问题,通常被称为“股票买卖问题(含手续费)”。问题的核心是:给定一个股票价格数组 prices 和一个交易手续费 fee,你可以进行多次交易,但每次卖出股票时需要支付手续费。目标是最大化利润。

代码思路解析:

1. 问题分析

  • 每天有两种状态:

    1. 持有股票f[i]):表示第 i 天结束时持有股票的最大利润。

    2. 不持有股票g[i]):表示第 i 天结束时没有股票的最大利润。

  • 目标是找到最后一天的最大利润。

2. 动态规划定义

  • 定义两个状态数组 f 和 g

    • f[i] 表示第 i 天结束时持有股票的最大利润。

    • g[i] 表示第 i 天结束时没有股票的最大利润。

3. 状态转移方程

  • 持有股票f[i]):

    • 可能是前一天就持有股票,即 f[i-1]

    • 也可能是今天买入股票,那么前一天必须没有股票,即 g[i-1] - prices[i]

    • 取两者的最大值:

      f[i] = max(f[i-1], g[i-1] - prices[i]);
  • 不持有股票g[i]):

    • 可能是前一天就没有股票,即 g[i-1]

    • 也可能是今天卖出股票,那么前一天必须持有股票,即 f[i-1] + prices[i] - fee

    • 取两者的最大值:

      g[i] = max(g[i-1], f[i-1] + prices[i] - fee);

4. 初始化

  • 第 0 天(初始状态):

    • f[0] = -prices[0]:第 0 天买入股票,利润为 -prices[0]

    • g[0] = 0:第 0 天不持有股票,利润为 0

5. 填表

  • 从 i = 1 开始,逐步计算 f[i] 和 g[i],直到 i = n-1

6. 返回结果

  • 最终的结果是 g[n-1],即最后一天不持有股票的最大利润。

优化空间复杂度:

当前的空间复杂度是 O(n),可以通过滚动数组的方式优化到 O(1)

class Solution {
public:int maxProfit(vector<int>& prices, int fee) {int n = prices.size();if (n == 0) return 0; // 边界条件处理// 使用滚动数组优化空间复杂度int f = -prices[0]; // 持有股票int g = 0;          // 不持有股票for (int i = 1; i < n; i++) {int new_f = max(f, g - prices[i]); // 持有股票int new_g = max(g, f + prices[i] - fee); // 不持有股票f = new_f;g = new_g;}// 返回结果return g;}
};

总结:

  • 使用动态规划的思想,通过状态转移方程计算每天的最大利润。

  • 通过滚动数组优化,空间复杂度从 O(n) 降低到 O(1)

  • 最终结果是最后一天不持有股票的最大利润。

七、123. 买卖股票的最佳时机 III - 力扣(LeetCode) 

算法代码:

class Solution {
public:const int INF = 0x3f3f3f3f; // 表示无穷大int maxProfit(vector<int>& prices) {int n = prices.size();if (n == 0) return 0; // 边界条件处理// f[i][j] 表示第 i 天结束时,完成了 j 笔交易并持有股票的最大利润// g[i][j] 表示第 i 天结束时,完成了 j 笔交易并不持有股票的最大利润vector<vector<int>> f(n, vector<int>(3, -INF));vector<vector<int>> g(n, vector<int>(3, -INF));// 初始化f[0][0] = -prices[0]; // 第 0 天买入股票g[0][0] = 0;          // 第 0 天不持有股票// 填表for (int i = 1; i < n; i++) {for (int j = 0; j < 3; j++) {f[i][j] = max(f[i - 1][j], g[i - 1][j] - prices[i]); // 持有股票g[i][j] = g[i - 1][j]; // 不持有股票if (j >= 1) // 如果该状态存在g[i][j] = max(g[i][j], f[i - 1][j - 1] + prices[i]); // 卖出股票}}// 找到最后一行的最大值int ret = 0;for (int j = 0; j < 3; j++)ret = max(ret, g[n - 1][j]);return ret;}
};

        这个代码实现了一个动态规划问题,通常被称为“股票买卖问题(最多完成两笔交易)”。问题的核心是:给定一个股票价格数组 prices,你最多可以完成两笔交易(买入和卖出算一笔交易),目标是最大化利润。

代码思路解析:

1. 问题分析

  • 每天有两种状态:

    1. 持有股票f[i][j]):表示第 i 天结束时,完成了 j 笔交易并持有股票的最大利润。

    2. 不持有股票g[i][j]):表示第 i 天结束时,完成了 j 笔交易并不持有股票的最大利润。

  • 目标是找到最后一天的最大利润。

2. 动态规划定义

  • 定义两个状态数组 f 和 g

    • f[i][j] 表示第 i 天结束时,完成了 j 笔交易并持有股票的最大利润。

    • g[i][j] 表示第 i 天结束时,完成了 j 笔交易并不持有股票的最大利润。

  • j 的取值范围是 012,表示完成的交易笔数。

3. 状态转移方程

  • 持有股票f[i][j]):

    • 可能是前一天就持有股票,即 f[i-1][j]

    • 也可能是今天买入股票,那么前一天必须没有股票,即 g[i-1][j] - prices[i]

    • 取两者的最大值:

      f[i][j] = max(f[i-1][j], g[i-1][j] - prices[i]);
  • 不持有股票g[i][j]):

    • 可能是前一天就没有股票,即 g[i-1][j]

    • 也可能是今天卖出股票,那么前一天必须持有股票,且交易笔数增加 1,即 f[i-1][j-1] + prices[i]

    • 取两者的最大值:

      g[i][j] = max(g[i-1][j], f[i-1][j-1] + prices[i]);

4. 初始化

  • 第 0 天(初始状态):

    • f[0][0] = -prices[0]:第 0 天买入股票,利润为 -prices[0]

    • g[0][0] = 0:第 0 天不持有股票,利润为 0

    • 其他状态初始化为 -INF(表示不可达状态)。

5. 填表

  • 从 i = 1 开始,逐步计算 f[i][j] 和 g[i][j],直到 i = n-1

6. 返回结果

  • 最终的结果是 max(g[n-1][0], g[n-1][1], g[n-1][2]),即最后一天不持有股票的最大利润。

优化空间复杂度:

当前的空间复杂度是 O(n),可以通过滚动数组的方式优化到 O(1)

class Solution {
public:const int INF = 0x3f3f3f3f; // 表示无穷大int maxProfit(vector<int>& prices) {int n = prices.size();if (n == 0) return 0; // 边界条件处理// 使用滚动数组优化空间复杂度vector<int> f(3, -INF); // 持有股票vector<int> g(3, -INF); // 不持有股票// 初始化f[0] = -prices[0]; // 第 0 天买入股票g[0] = 0;          // 第 0 天不持有股票// 填表for (int i = 1; i < n; i++) {vector<int> new_f(3, -INF);vector<int> new_g(3, -INF);for (int j = 0; j < 3; j++) {new_f[j] = max(f[j], g[j] - prices[i]); // 持有股票new_g[j] = g[j]; // 不持有股票if (j >= 1) // 如果该状态存在new_g[j] = max(new_g[j], f[j - 1] + prices[i]); // 卖出股票}f = new_f;g = new_g;}// 找到最后一行的最大值int ret = 0;for (int j = 0; j < 3; j++)ret = max(ret, g[j]);return ret;}
};

总结:

  • 使用动态规划的思想,通过状态转移方程计算每天的最大利润。

  • 通过滚动数组优化,空间复杂度从 O(n) 降低到 O(1)

  • 最终结果是最后一天不持有股票的最大利润(最多完成两笔交易)。

八、 188. 买卖股票的最佳时机 IV - 力扣(LeetCode)

算法代码:

class Solution {
public:const int INF = 0x3f3f3f3f; // 表示无穷大int maxProfit(int k, vector<int>& prices) {int n = prices.size();if (n == 0) return 0; // 边界条件处理// 处理一个细节问题:最多只能完成 n/2 笔交易k = min(k, n / 2);// f[i][j] 表示第 i 天结束时,完成了 j 笔交易并持有股票的最大利润// g[i][j] 表示第 i 天结束时,完成了 j 笔交易并不持有股票的最大利润vector<vector<int>> f(n, vector<int>(k + 1, -INF));vector<vector<int>> g(n, vector<int>(k + 1, -INF));// 初始化f[0][0] = -prices[0]; // 第 0 天买入股票g[0][0] = 0;          // 第 0 天不持有股票// 填表for (int i = 1; i < n; i++) {for (int j = 0; j <= k; j++) {f[i][j] = max(f[i - 1][j], g[i - 1][j] - prices[i]); // 持有股票g[i][j] = g[i - 1][j]; // 不持有股票if (j >= 1) // 如果该状态存在g[i][j] = max(g[i][j], f[i - 1][j - 1] + prices[i]); // 卖出股票}}// 找到最后一行的最大值int ret = 0;for (int j = 0; j <= k; j++)ret = max(ret, g[n - 1][j]);return ret;}
};

        这个代码实现了一个动态规划问题,通常被称为“股票买卖问题(最多完成 k 笔交易)”。问题的核心是:给定一个股票价格数组 prices 和一个整数 k,你最多可以完成 k 笔交易(买入和卖出算一笔交易),目标是最大化利润。

代码思路解析:

1. 问题分析

  • 每天有两种状态:

    1. 持有股票f[i][j]):表示第 i 天结束时,完成了 j 笔交易并持有股票的最大利润。

    2. 不持有股票g[i][j]):表示第 i 天结束时,完成了 j 笔交易并不持有股票的最大利润。

  • 目标是找到最后一天的最大利润。

2. 动态规划定义

  • 定义两个状态数组 f 和 g

    • f[i][j] 表示第 i 天结束时,完成了 j 笔交易并持有股票的最大利润。

    • g[i][j] 表示第 i 天结束时,完成了 j 笔交易并不持有股票的最大利润。

  • j 的取值范围是 0 到 k,表示完成的交易笔数。

3. 状态转移方程

  • 持有股票f[i][j]):

    • 可能是前一天就持有股票,即 f[i-1][j]

    • 也可能是今天买入股票,那么前一天必须没有股票,即 g[i-1][j] - prices[i]

    • 取两者的最大值:

      f[i][j] = max(f[i-1][j], g[i-1][j] - prices[i]);
  • 不持有股票g[i][j]):

    • 可能是前一天就没有股票,即 g[i-1][j]

    • 也可能是今天卖出股票,那么前一天必须持有股票,且交易笔数增加 1,即 f[i-1][j-1] + prices[i]

    • 取两者的最大值:

      g[i][j] = max(g[i-1][j], f[i-1][j-1] + prices[i]);

4. 初始化

  • 第 0 天(初始状态):

    • f[0][0] = -prices[0]:第 0 天买入股票,利润为 -prices[0]

    • g[0][0] = 0:第 0 天不持有股票,利润为 0

    • 其他状态初始化为 -INF(表示不可达状态)。

5. 填表

  • 从 i = 1 开始,逐步计算 f[i][j] 和 g[i][j],直到 i = n-1

6. 返回结果

  • 最终的结果是 max(g[n-1][0], g[n-1][1], ..., g[n-1][k]),即最后一天不持有股票的最大利润。

优化空间复杂度:

当前的空间复杂度是 O(n * k),可以通过滚动数组的方式优化到 O(k)

class Solution {
public:const int INF = 0x3f3f3f3f; // 表示无穷大int maxProfit(int k, vector<int>& prices) {int n = prices.size();if (n == 0) return 0; // 边界条件处理// 处理一个细节问题:最多只能完成 n/2 笔交易k = min(k, n / 2);// 使用滚动数组优化空间复杂度vector<int> f(k + 1, -INF); // 持有股票vector<int> g(k + 1, -INF); // 不持有股票// 初始化f[0] = -prices[0]; // 第 0 天买入股票g[0] = 0;          // 第 0 天不持有股票// 填表for (int i = 1; i < n; i++) {vector<int> new_f(k + 1, -INF);vector<int> new_g(k + 1, -INF);for (int j = 0; j <= k; j++) {new_f[j] = max(f[j], g[j] - prices[i]); // 持有股票new_g[j] = g[j]; // 不持有股票if (j >= 1) // 如果该状态存在new_g[j] = max(new_g[j], f[j - 1] + prices[i]); // 卖出股票}f = new_f;g = new_g;}// 找到最后一行的最大值int ret = 0;for (int j = 0; j <= k; j++)ret = max(ret, g[j]);return ret;}
};

总结:

  • 使用动态规划的思想,通过状态转移方程计算每天的最大利润。

  • 通过滚动数组优化,空间复杂度从 O(n * k) 降低到 O(k)

  • 最终结果是最后一天不持有股票的最大利润(最多完成 k 笔交易)。

相关文章:

简单多状态 dp 问题(典型算法思想)—— OJ例题算法解析思路

目录 一、面试题 17.16. 按摩师 - 力扣&#xff08;LeetCode&#xff09; 算法代码&#xff1a; 代码思路解析&#xff1a; 问题分析&#xff1a; 动态规划定义&#xff1a; 状态转移方程&#xff1a; 初始化&#xff1a; 填表&#xff1a; 返回值&#xff1a; 优化空…...

【电路笔记 TMS320C6***DSP】外部存储器接口 A EMIFA向FPGA(作为异步存储器)写入数据的示例

目录 DSP和FPGA的连接DSP端&#xff1a;传输数据给FPGAFPGA端&#xff1a;接收数据 EMIFA&#xff08;External Memory Interface A&#xff09;的“异步存储器”&#xff08;Asynchronous Memory&#xff09;指的是那些不与系统时钟同步进行读写操作的外部存储设备。这类存储器…...

pgsql 查看数据库、表、索引大小等

查询数据库大小 -- 查询单个数据库大小 select pg_size_pretty(pg_database_size(postgres)) as size;-- 查询所有数据库大小 select datname, pg_size_pretty (pg_database_size(datname)) AS size from pg_database; 查询表大小 -- 查询单个表大小 select pg_size_pretty(p…...

物联网感知层采集的数据 经过etl 后 ,输送给ai 训练模型 和模型本身调优

在物联网(IoT)系统中,感知层采集的数据经过 ETL(Extract, Transform, Load) 处理后,可以作为 AI 模型的训练数据,用于模型训练和调优。以下是实现这一过程的详细步骤和技术方案: 一、数据流程概述 数据采集:通过传感器和物联网设备采集原始数据。ETL 处理:对原始数据…...

C语言基础

一、基础 C语言文件 后缀 .c为源文件 .h为头文件 以 Visual studio 为例右键点击源文件点击添加&#xff0c;新建项 .c为C语言文件&#xff0c;.cpp为C文件 后缀不同编译器会按照不同的编译语法进行编译 .cpp以C语法 第一个程序 #include <stdio.h> //包含 st…...

pinginfoview网络诊断工具中文版

介绍 pinginfoview中文版本是一款实用的网络诊断工具&#xff0c;它专为中文用户设计&#xff0c;提供了方便易用的界面&#xff0c;使得在Windows环境下进行ping测试变得更加简单。该工具是由NirSoft开发的一款免费的桌面应用程序&#xff0c;尽管官方可能并未正式发布中文版…...

Anyting LLM LLM温度设置范围

在Anything LLM中&#xff0c;LLM&#xff08;Language Model&#xff09;的温度设置是一个关键参数&#xff0c;它影响着模型生成文本时的随机性和确定性。关于Anything LLM的LLM温度设置范围&#xff0c;虽然没有官方的明确数值范围说明&#xff0c;但通常温度参数的设置遵循…...

鸿蒙Android4个脚有脚线

效果 min:number122max:number150Row(){Stack(){// 底Text().border({width:2,color:$r(app.color.yellow)}).height(this.max).aspectRatio(1)// 长Text().backgroundColor($r(app.color.white)).height(this.max).width(this.min)// 宽Text().backgroundColor($r(app.color.w…...

RecyclerView与ListView的优化

RecyclerView与ListView的优化 一、基础概念对比 1.1 ListView与RecyclerView概述 ListView和RecyclerView都是Android中用于展示列表数据的重要控件&#xff0c;但RecyclerView是更现代化的解决方案&#xff0c;提供了更多的灵活性和性能优势。 ListView特点 Android早期…...

【人工智能】GPT-4 vs DeepSeek-R1:谁主导了2025年的AI技术竞争?

前言 2025年&#xff0c;人工智能技术将迎来更加激烈的竞争。随着OpenAI的GPT-4和中国初创公司DeepSeek的DeepSeek-R1在全球范围内崭露头角&#xff0c;AI技术的竞争格局开始发生变化。这篇文章将详细对比这两款AI模型&#xff0c;从技术背景、应用领域、性能、成本效益等多个方…...

2025年Cursor最新安装使用教程

Cursor安装教程 一、Cursor下载二、Cursor安装三、Cursor编辑器快捷键(1) 基础编辑快捷键(2) 导航快捷键(3) 其他常用快捷键 一、Cursor下载 Cursor官方网站&#xff08;https://www.cursor.com/ &#xff09; 根据自己电脑操作系统选择对应安装包 二、Cursor安装 下载完成后…...

原码、反码和补码的介绍和区别

在计算机中&#xff0c;有符号整数的表示方法主要有 原码、反码和补码&#xff0c;它们解决了二进制数表示正负数及简化运算的问题。以下是分步说明&#xff1a; 1. 原码&#xff08;Sign-Magnitude&#xff09; 定义&#xff1a;最高位为符号位&#xff08;0正1负&#xff09…...

STM32 进阶 定时器

在stm32中定时器大概分为4类 1、系统定时器&#xff1a;属于arm内核&#xff0c;内嵌在NVIC中 2、高级定时器&#xff1a;可以用来刹车和死区 3、通用定时器&#xff1a;可以用来输出pwm方波 4、基本定时器&#xff1a;只能记数 系统定时器注意&#xff1a; 1、系统定时器…...

山东大学:《DeepSeek应用与部署》

大家好&#xff0c;我是吾鳴。 今天吾鳴要给大家分享一份由山东大学出版的DeepSeek报告——《DeepSeek应用与部署》&#xff0c;这份报告讲述了AIGC的发展历程&#xff0c;DeepSeek应用场景和DeepSeek如何本地化部署。报告一共80页PPT&#xff0c;文末有完整版下载地址。 内容摘…...

【无标题】FrmImport

文章目录 前言一、问题描述二、解决方案三、软件开发&#xff08;源码&#xff09;四、项目展示五、资源链接 前言 我能抽象出整个世界&#xff0c;但是我不能抽象你。 想让你成为私有常量&#xff0c;这样外部函数就无法访问你。 又想让你成为全局常量&#xff0c;这样在我的…...

Android14 OTA升级

因Vendor Freeze的缘故,若开启Non-AB OTA, 则会遇到交叉编译vendor和system的增量升级包时需要检查fingerprint而导致编译失败,从而无法做到增量升级包升级。高版本一般都是打开AB模式。 AB 和 non AB 切换相关宏 /vendor_ap_s0/device/mediatek/system/mssi_64_cn/SystemCo…...

监听 RabbitMQ 延时交换机的消息数、OpenFeign 路径参数传入斜杠无法正确转义

背景 【MQ】一套为海量消息和高并发热点消息&#xff0c;提供高可用精准延时服务的解决方案 我现在有一个需求&#xff0c;就是监听 RabbitMQ 一个延时交换机的消息数&#xff0c;而 RabbitTemplate 是不存在对应的方法来获取的。 而我们在 RabbitMQ 的控制台却可以发现延时交…...

宇树科技嵌入式面试题及参考答案(春晚机器人的公司)

目录 设计一个带看门狗(Watchdog)的嵌入式系统,描述故障恢复流程 在资源受限的 MCU 上实现 OTA 升级功能,描述关键设计点 如何实现 OTA(空中升级)功能?描述固件校验和回滚机制的设计要点 推挽输出与开漏输出的区别?举例说明其在 GPIO 控制中的应用 UART、SPI、I2C …...

Linux内核自定义协议族开发指南:理解net_device_ops、proto_ops与net_proto_family

在Linux内核中开发自定义协议族需要深入理解网络协议栈的分层模型。net_device_ops、proto_ops和net_proto_family是三个关键结构体,分别作用于不同的层次。本文将详细解析它们的作用、交互关系及实现方法,并提供一个完整的开发框架。 一、核心结构体的作用与层级关系 struct…...

【Go语言快速上手】第一部分:数据类型(数组、切片、映射)与控制语句

文章目录 一、复合类型Ⅰ 数组1. 语法2. 示例3. 特点4. 数组的传递 Ⅱ 切片1. 定义2. 语法3. 示例4. 特点5. 切片的创建6. 切片的操作切片的扩展切片的拷贝 Ⅲ 映射1. 定义2. 语法3. 示例4. 特点5. 映射的创建6. 映射的操作示例&#xff1a;插入、访问和删除判断键是否存在示例…...

系统架构评估中的重要概念

(1)敏感点(Sensitivity Point) 和权衡点 (Tradeoff Point)。敏感点和权衡点是关键的架构 决策。敏感点是一个或多个构件(和/或构件之间的关系)的特性。研究敏感点可使设计人员 或分析员明确在搞清楚如何实现质量目标时应注意什么。权衡点是影响多个质量属性的特性&#xff0c; …...

shell逐行读取文件 远程操作服务器

代码示例 while read ip; doecho "uninstalling test programs in $line" ssh root$ip bash -s < remote_remove_tool.shdone < installed_ips总结 ✅ 作用&#xff1a; 逐行读取 installed_ips 文件中的 IP 地址通过 SSH 连接到远程服务器&#xff…...

盛铂科技SCP4000射频微波功率计与SPP5000系列脉冲峰值 USB功率计 区别

在射频&#xff08;RF&#xff09;和微波测试领域&#xff0c;快速、精准的功率测量是确保通信系统、雷达、卫星设备等高性能运行的核心需求。无论是连续波&#xff08;CW&#xff09;信号的稳定性测试&#xff0c;还是脉冲信号的瞬态功率分析&#xff0c;工程师都需要轻量化、…...

【每日八股】计算机网络篇(三):IP

目录 DNS 查询服务器的基本流程DNS 采用 TCP 还是 UDP&#xff0c;为什么&#xff1f;默认使用 UDP 的原因需要使用 TCP 的场景&#xff1f;总结 DNS 劫持是什么&#xff1f;解决办法&#xff1f;浏览器输入一个 URL 到显示器显示的过程&#xff1f;URL 解析TCP 连接HTTP 请求页…...

vtk 3D坐标标尺应用 3D 刻度尺

2d刻度尺 : vtk 2D 刻度尺 2D 比例尺-CSDN博客 简介&#xff1a; 3D 刻度尺&#xff0c;也是常用功能&#xff0c;功能强大 3D 刻度尺 CubeAxesActor vtkCubeAxes调整坐标轴的刻度、原点和显示效果&#xff0c;包括关闭小标尺、固定坐标轴原点&#xff0c;以及设置FlyMode模…...

探秘基带算法:从原理到5G时代的通信变革【十】基带算法应用与对比

文章目录 三、算法在现代通信系统中的应用3.1 5G 通信中的应用3.1.1 信道编码与调制解调3.1.2 大规模 MIMO 技术3.1.3 案例分析&#xff1a;5G 基站与终端实现 3.2 卫星通信中的应用3.2.1 抗干扰与纠错编码3.2.2 信号处理与调制解调3.2.3 案例分析&#xff1a;卫星通信系统实例…...

消费级、工业级、汽车级、军工级、航天级芯片区别对比

汽车电子行业&#xff0c;经常会由于降本原因&#xff0c;听到“消规、工规、车规”方面的讨论。常见的芯片等级一般是按照使用温度、辐射、抗干扰等来分级。等级分为以下5类: 民用级&#xff08;消费级&#xff09;、工业级、汽车级&#xff08;车规级&#xff09;、军工级、航…...

迷你世界脚本背包接口:Backpack

背包接口&#xff1a;Backpack 彼得兔 更新时间: 2023-10-25 10:29:21 具体函数名及描述如下: 序号 函数名 函数描述 1 getBackpackBarIDRange(...) 获取道具背包栏ID范围(起始ID~结束ID) 2 getBackpackBarSize(...) 获取道具背包栏大小 3 setGridItem(.…...

javaSE基础

java跨平台性&#xff1a; Java 语言编写的程序&#xff0c;一次编译后&#xff0c;可以在多个操作系统上运行。是由于其增加了一个中间件 JVM&#xff0c;JVM 负责将 Java 字节码转换为特定平台的机器码&#xff0c;并执行。 Java 程序从源代码到运行需要经过三步&#xff1a…...

电脑的系统版本是windows7的,下载pycharm的哪个版本比较好呢?

李升伟 整理 在Windows 7系统上选择PyCharm版本时&#xff0c;需综合考虑系统兼容性、Python版本适配性以及开发需求。以下是具体建议和操作指南&#xff1a; 1. 选择PyCharm的兼容版本 推荐版本&#xff1a;PyCharm 2020.3.5及之前的旧版本。 原因&#xff1a;自2021年起&a…...

【前端基础】3、HTML的常用元素(h、p、img、a、iframe、div、span)、不常用元素(strong、i、code、br)

HTML结构 一个HTML包含以下部分&#xff1a; 文档类型声明html元素 head元素body元素 例&#xff08;CSDN&#xff09;&#xff1a; 一、文档类型声明 HTML最一方的文档称为&#xff1a;文档类型声明&#xff0c;用于声明文档类型。即&#xff1a;<!DOCTYPE html>…...

安装mysql

1、安装数据库 下载链接 https://downloads.mysql.com/archives/community/ 下载zip安装包&#xff0c;解压到某个路径下&#xff0c;将bin文件夹添加到系统环境变量 。 然后终端输入指令 mysql --version 验证 2、初始化数据库 打开命令提示符&#xff08;以管理员身份&am…...

关于 QPalette设置按钮背景未显示出来 的解决方法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/146047054 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…...

记一次ScopeSentry搭建

介绍 Scope Sentry是一款具有资产测绘、子域名枚举、信息泄露检测、漏洞扫描、目录扫描、子域名接管、爬虫、页面监控功能的工具&#xff0c;通过构建多个节点&#xff0c;自由选择节点运行扫描任务。当出现新漏洞时可以快速排查关注资产是否存在相关组件。 目前功能 插件系…...

【每日学点HarmonyOS Next知识】Web Header更新、状态变量嵌套问题、自定义弹窗、stack圆角、Flex换行问题

【每日学点HarmonyOS Next知识】Web Header更新、状态变量嵌套问题、自定义弹窗、stack圆角、Flex换行问题 1、HarmonyOS 有关webview Header无法更新的问题&#xff1f; 业务A页面 打开 webivew B页面&#xff0c;第一次打开带了header请求&#xff0c;然后退出webview B页面…...

优选算法的智慧之光:滑动窗口专题(二)

专栏&#xff1a;算法的魔法世界​​​​​​ 个人主页&#xff1a;手握风云 目录 一、例题讲解 1.1. 最大连续1的个数 III 1.2. 找到字符串中所有字母异位词 1.3. 串联所有单词的子串 1.4. 最小覆盖子串 一、例题讲解 1.1. 最大连续1的个数 III 题目要求是二进制数组&am…...

Android ChatOn-v1.66.536-598-[构建于ChatGPT和GPT-4o之上]

ChatOn 链接&#xff1a;https://pan.xunlei.com/s/VOKYnq-i3C83CK-HJ1gfLf4gA1?pwdwzwc# 添加了最大无限积分 删除了所有调试信息 语言&#xff1a;全语言支持...

十一、Redis Sentinel(哨兵)—— 高可用架构与配置指南

Redis Sentinel(哨兵)—— 高可用架构与配置指南 在分布式应用中,Redis 主从复制(Master-Slave)虽然能提供读写分离的能力,但它 无法自动故障转移(failover)。如果主节点(Master)发生故障,系统管理员需要手动将某个从节点(Slave)提升为主节点,并重新配置所有从节…...

【STM32】玩转IIC之驱动MPU6050及姿态解算

目录 前言 一.MPU6050模块介绍 1.1MPU6050简介 1.2 MPU6050的引脚定义 1.3MPU6050寄存器解析 二.MPU6050驱动开发 2.1 配置寄存器 2.2对MPU6050寄存器进行读写 2.2.1 写入寄存器 2.2.2读取寄存器 2.3 初始化MPU6050 2.3.1 设置工作模式 2.3.2 配置采样率 2.3.3 启…...

《张一鸣,创业心路与算法思维》

张一鸣&#xff0c;多年如一日的阅读习惯。 爱读人物传记&#xff0c;称教科书式人类知识最浓缩的书&#xff0c;也爱看心理学&#xff0c;创业以及商业管理类的书。 冯仑&#xff0c;王石&#xff0c;联想&#xff0c;杰克韦尔奇&#xff0c;思科。 《乔布斯传》《埃隆马斯…...

深入浅出:UniApp 从入门到精通全指南

https://juejin.cn/post/7440119937644101684 uni-app官网 uniapp安卓离线打包流程_uniapp离线打包-CSDN博客 本文是关于 UniApp 从入门到精通的全指南&#xff0c;涵盖基础入门&#xff08;环境搭建、创建项目、项目结构、编写运行&#xff09;、核心概念与进阶知识&#x…...

低空经济-飞行数据平台 搭建可行方案

搭建一个飞行数据平台是低空经济中至关重要的一环,它能够实现对飞行器的实时监控、数据分析、路径优化以及安全管理。以下是搭建飞行数据平台的详细步骤和技术方案: 一、平台的核心功能 实时监控: 实时获取飞行器的位置、速度、高度、电池状态等数据。提供可视化界面,展示飞…...

【四.RAG技术与应用】【12.阿里云百炼应用(下):RAG的云端优化与扩展】

在上一篇文章中,我们聊了如何通过阿里云百炼平台快速搭建一个RAG(检索增强生成)应用,实现文档智能问答、知识库管理等基础能力。今天咱们继续深入,聚焦两个核心问题:如何通过云端技术优化RAG的效果,以及如何扩展RAG的应用边界。文章会穿插实战案例,手把手带你踩坑避雷。…...

3-7 WPS JS宏 工作表移动复制实例-2(多工作簿的多工作表合并)学习笔记

************************************************************************************************************** 点击进入 -我要自学网-国内领先的专业视频教程学习网站 *******************************************************************************************…...

【智能机器人开发全流程:硬件选型、软件架构与ROS实战,打造高效机器人系统】

文章目录 1. 硬件层设计(1) 传感器选型(2) 计算平台 2. 软件架构设计(1) 核心模块划分(2) 通信框架 3. 关键实现步骤(1) 硬件-软件接口开发(2) SLAM与导航实现(3) 仿真与测试 4. 典型框架示例基于ROS的移动机器人分层架构 5. 优化与扩展6. 开源项目参考 1. 硬件层设计 (1) 传感…...

【CSS—前端快速入门】CSS 选择器

CSS 1. CSS介绍 1.1 什么是CSS? CSS(Cascading Style Sheet)&#xff0c;层叠样式表&#xff0c;用于控制页面的样式&#xff1b; CSS 能够对网页中元素位置的排版进行像素级精确控制&#xff0c;实现美化页面的效果&#xff1b;能够做到页面的样式和 结构分离&#xff1b; 1…...

二、QT和驱动模块实现智能家居-----5、通过QT控制LED

在QT界面&#xff0c;我们要实现点击“LED”按钮就可以控制板子上的LED。LED接线图如下&#xff1a; 在Linux 系统里&#xff0c;我们可以使用2种方法去操作上面的LED&#xff1a; ① 使用GPIO SYSFS系统&#xff1a;这需要一定的硬件知识&#xff0c;需要设置引脚的方向、数值…...

在UI设计中使用自定义控件

生成&#xff1a; 自定义控件完成&#xff1a; 看控件的父类是谁&#xff1a; 在想使用的窗口中&#xff1a; 拖动一个与他父类相同类型的控件&#xff1a; 点击控件右键 这样就是你自定义的控件了 运行后&#xff1a; //点击QSpinBox&#xff0c;滑块跟着移动void (QSpinBox::…...

docker 离线安装redis(离线)

docker离线安装redis时&#xff0c;我找了挺多资料都是需要先在另一台能联网的机器上先下载镜像&#xff0c;然后移动内网中的docker服务器进行部署&#xff0c;我也是这么操作的&#xff0c;但是必须拥有能上网的docker环境才能下载&#xff0c;我在github上找到了一种可以直接…...

利用python实现对Excel文件中数据元组的自定义排序

问题引入&#xff1a; 假设你是一个浙江省水果超市的老板&#xff0c;统筹11个下辖地市的水果产量。假设11个地市生产的水果包括&#xff1a;苹果、香蕉和西瓜。你如何快速得到某种水果产量突出&#xff08;排名前几&#xff09;的地市&#xff1f;产量落后&#xff08;排名后…...