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

动态规划dp专题-(上)

目录

dp理论知识🔥🔥

🎯一、线性DP

(1)🚀斐波那契数 -入门级

(2)🚀898. 数字三角形-acwing ---入门级

 (3)往期题目

①选数异或:在 [l, r] 区间是否能找到 a[i] ^ a[j] = x 的数对?

 ②🚀破损的楼梯:

 ③🚀安全序列:

 🎯二、背包问题 ✅✅✅【很重要!!】

(1)  494. 目标和 - 力扣 --(0-1背包) 【给定背包容量,装满背包有多少种方法】

 🤯🤯🤯🤯🤯🤯🤯🤯🤯

(2)322. 零钱兑换 - 力扣(完全背包)--

(3)518. 零钱兑换 II - 力扣(完全背包)-和25-3-2的csp题基本一样

(4)377. 组合总和 Ⅳ - 力扣(LeetCode) --完全背包

(5)57. 爬楼梯 (卡玛)

 🤯🤯🤯🤯🤯🤯🤯🤯🤯

(6)46. 携带研究材料(0-1背包)【 给定背包容量 装满背包 的最大价值是多少】

 (7)最快洗车时间(0-1)背包 

(8)474. 一和零 - 力扣 (0-1背包)【给定背包容量,装满背包最多有多少个物品】

(9)279. 完全平方数 -(完全背包) 

🎯三、子序列LSCDP 【线性DP的一个分支】

(1)895. 最长上升子序列 - AcWing题库

(2)674. 最长连续递增序列 - 力扣(LeetCode)

 (3)最长公共子序列 - acwing

(4)1035. 不相交的线 - 力扣

(5)718. 最长重复子数组 - (最长连续公共子序列)

(6)53. 最大子数组和 - 力扣

 (7) 392. 判断子序列 - 力扣 

(8)拍照【最长山峰子序列】---已发博客,点击标题跳转

(9)72. 编辑距离 - 力扣


dp理论知识🔥🔥

        很多讲解动态规划的文章都会讲最优子结构啊和重叠子问题啊这些,这些东西都是教科书的上定义,晦涩难懂而且不实用。家知道动规是由前一个状态推导出来的对于刷题来说就够用的。

        通常用于求解 最值问题(最大值、最小值、最短路径等)或 计数问题(方案总数等),一般看到题目中有"最大/最小"、"最多/最少"、"最长/最短"、"最高/最低、"有多少种方法"、"可能的方案数"、"不同方式的数量"等可以考虑是否用dp。

动态规划,一般分为5个步骤:

①确定dp数组以及下标的含义

就是 dp[i] 这个值,是什么意思?以i为结尾,如何如何;或者以i为起点,如何如何。

🌰dp[i][j] 表示 A 的前 i 个字符和 B 的前 j 个字符的最长公共子序列

 dp[i][j] 表示二维网格中从 (0,0) 到 (i,j) 的最短路径

 dp[i][j] 表示考虑前 i 件物品,背包容量为 j 时的最大价值

    dp[i] 表示以 nums[i] 结尾的最长递增子序列长度

②确定递推公式【状态转移方程】(核心)

状态转移方程就是:dp[i] 等于什么 ?【我的经验是多做题,一般都是模版题或者模版题的变形】

状态转移方程,就是根据 dp[ i ] 之前或者 dp[ i ] 之后,来推导出 dp[ i ] 的值
只要你能根据之前或或者之后的值来推导出 dp[ i ] 的值,那么,状态转移方程就出来了
但是,怎么推?
        这个就要就题目而言,大体的思路是这样的:根据最近的状态来划分问题
 一般来说,dp[i] 的值,要么是前面的 dp[i-1] 或者后面的 dp[i+1],一定要十分明确dp数组的含义

③dp数组如何初始化

初始化就是保证,在我们进行填表的时候不越界,dp[0]dp[1] 是多少?
例如说,我要求 dp[0] / dp[1] 的值,需要前面的位置,但是此时明显已经越界
因此,这两个位置需要单独处理

④确定遍历(填表)顺序 :从前往后还是从后往前?

什么是填表顺序?

如i位置值得求解,需要前面两个位置的值已经存在才能求解
因此,也就是说在算i位置时,i-1 和 i-2 位置已经填了,已经有值了
所以,我们的填表顺序应该是从前往后,因为后面的值的求解需要前面的值
反之,就是从后往前。

⑤举例推导dp数组

代入具体数值,检查推导是否正确

        动态规划应该如何debug? 找问题的最好方式就是把dp数组打印出来,看看究竟是不是按照自己思路推导的! 

如果代码写出来了,一直AC不了,灵魂三问:

  1. 这道题目我举例推导状态转移公式了么?
  2. 我打印dp数组的日志了么?
  3. 打印出来了dp数组和我想的一样么?

🎯一、线性DP

emm 比较基础的DP问题,挺简单的-求解具有线性结构的最优子问题

 线性DP指问题的状态转移沿单一维度展开,通常表现为:

  • 状态定义在一维数组线性序列(如字符串、数组)上

  • 状态转移方程仅依赖前序有限个状态

dp[i]:以第i个元素结尾的最优解     dp[i]:前i个元素构成的子问题的解


(1)🚀斐波那契数 -入门级

https://leetcode.cn/problems/fibonacci-number/description/

 509. 斐波那契数 - 力扣(LeetCode) ----写的超好的一篇题解!!!最有收获的一段话:

 ① dp[i]的定义为:第i个数的斐波那契数值是dp[i]

题目已经把递推公式直接给我们了:状态转移方程 dp[i] = dp[i - 1] + dp[i - 2];

③dp数组如何初始化:dp[0]=0,dp[1]=1;    

④确定遍历顺序:从递归公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,dp[i]是依赖 dp[i - 1] 和 dp[i - 2],那么遍历的顺序一定是从前到后遍历的

⑤举例推导:

        按照这个递推公式dp[i] = dp[i - 1] + dp[i - 2],我们来推导一下,当N为10的时候,dp数组应该是如下的数列:

        0 1 1 2 3 5 8 13 21 34 55

        如果代码写出来,发现结果不对,就把dp数组打印出来看看和我们推导的数列是不是一致的。

class Solution {
public:int fib(int N) {if (N <= 1) return N;vector<int> dp(N + 1);dp[0] = 0;dp[1] = 1;for (int i = 2; i <= N; i++) {dp[i] = dp[i - 1] + dp[i - 2];}return dp[N];}
};

当然可以发现,我们只需要维护两个数值就可以了,不需要记录整个序列:将空间复杂度由n将为1

class Solution {
public:int fib(int N) {if (N <= 1) return N;int dp[2];dp[0] = 0;dp[1] = 1;for (int i = 2; i <= N; i++) {int sum = dp[0] + dp[1];dp[0] = dp[1];dp[1] = sum;}return dp[1];}
};

(2)🚀898. 数字三角形-acwing ---入门级

        如何确定状态转移方程呢?因为每个位置只能由上一层的相邻位置到达,也就是对于第i行第j列的位置,它只能从第i-1行的第j-1列或者第j列的位置下来(假设每行是从左到右编号的)。所以,状态转移方程应该是dp[i][j] = max(dp[i-1][j-1], dp[i-1][j]) + a[i][j],其中a[i][j]是三角形中第i行第j列的数字。 

#include<bits/stdc++.h>
using namespace std;
const int N=510;
int dp[N][N]; //dp[i][j]:到达第i行第j列的位置时,所能获得的最大路径和
int a[N][N];//三角形
int n;
int main(){cin>>n;for(int i=1;i<=n;i++){for(int j=1;j<=i;j++){cin>>a[i][j];}}//初始化memset(dp, -0x3f3f3f3f, sizeof dp); dp[1][1]=a[1][1];//dpfor(int i=2;i<=n;i++){for(int j=1;j<=i;j++){//转移方程dp[i][j]=max(dp[i-1][j-1],dp[i-1][j])+a[i][j];}}int res=INT_MIN;//最后一行找最大的for(int i=1;i<=n;i++){res=max(res,dp[n][i]);}cout<<res;return 0;
}

 (3)往期题目

【AcWing】动态规划-线性DP -选数异或-CSDN博客

【蓝桥】线性DP-破损的楼梯-CSDN博客

【蓝桥】线性DP-安全序列-CSDN博客

 回顾了一下这几道题目,简单总结下吧~

①选数异或:在 [l, r] 区间是否能找到 a[i] ^ a[j] = x 的数对?

dp[i] :在前 i 个元素中,能够与第 i 个元素构成异或为 x 的元素的最左位置

dp[i] = max(dp[i - 1], last[x ^ a])

这道题思维很奇特!!我真的想不到可以如此定义dp数组,第一遍看题解理解了好久,这次再回顾的时候一下就顿悟了哈哈哈,真的很有趣的一道题,不过我自己真的想不到这样的dp定义.......(题还是做少了吧·······)

 🚀破损的楼梯:

看到这道题目第一眼,很明显就是用dp解决(求方案数)

dp[i]:到第i级台阶的方案数

dp[i] = dp[i-1] +dp[i-2]

        dp数组的定义和转移方程都不难想到,其实就是斐波那契数列。,但是题目多了一个特殊条件(有破损的楼梯),(分情况!!)这里可以学到遇到破损的(障碍)时候应该如何应对,即让其dp[i] =0  ,到达破损楼梯的方案数为0,注意初始化 dp[0] =  1

 🚀安全序列:

类似“在长度为 n 的位置中,按照一定规则放置物品(如桶)”的问题。(求方案数)

需要分情况!!

我自己写的时候dp[i] 的含义很好猜前i个位置已经安放好的方案总数,然后我反推状态方程,也分了第 i 空位可以放桶和不可以放两种情况,还是很简单的一道题dp[i]=(dp[i-1]+1)   【不放】 当第i位放时,要求第i-k那不能放,此时dp[i]=dp[i-1] + dp[i-k-1]

注意初始化dp[0]=1(就是全空一种情况)

 🎯二、背包问题 ✅✅✅【很重要!!】

【Acwing】背包问题汇总--理解DP动态规划-CSDN博客  ---之前总结的背包的原始题目很详细了(yxc版本)我在原文章进一步优化了一下,直接看原文章的背包问题汇总叭~~~

下面几个是背包问题的应用,都是用的背包问题的模版(包括2025/3月份csp考试的第二题【与100分失之交臂!!!!啊啊】)

(1)  494. 目标和 - 力扣 --(0-1背包) 【给定背包容量,装满背包有多少种方法】

        emmm有点难度但是很有趣哇,不是简单套末班就可以AC的,每个数可以选择加或者减,那么总和的话,可以看成是把这些数分成两个子集,一个是正数的和,一个是负数的和的绝对值。假设正数的和是S,负数的和是total_sum - S。那么总的效果就是S - (total_sum - S) = target。也就是2S = target + total_sum。所以,我们需要找到有多少个子集,使得它们的和等于(target + total_sum)/2。 此时问题就转化为,用nums装满容量为(target + total_sum)/2的背包,有几种方法。

        然后套0-1背包问题的模版就好啦~~注意return 0 的两种情况

class Solution {
public:int findTargetSumWays(vector<int>& nums, int target) {// 计算数组的总和int sum = accumulate(nums.begin(), nums.end(), 0);// 如果 |target| > sum,说明不可能找到符合条件的子集,返回 0// 如果 (sum + target) 不是偶数,说明无法拆分成两个整数子集,返回 0if (abs(target) > sum || (sum + target) % 2 != 0) return 0;// 计算子集和 s,使得 P - N = target,且 P + N = sum// 解得 P = (sum + target) / 2,即找到一个子集 P 使其和为 sint s = (sum + target) / 2;// 定义 dp 数组,dp[j] 表示能够凑成 j 的方案数vector<int> dp(s + 1, 0);dp[0] = 1; // 只有一种方法能凑成 0,即什么都不选// 遍历每个数for (int num : nums) {// 逆序遍历 dp 数组,确保每个 num 只被使用一次(避免重复选择)for (int j = s; j >= num; j--) {// 状态转移:dp[j] 表示选择 num 之后的方案数dp[j] += dp[j - num];}}// 返回凑成 s 的方案数return dp[s];}
};

 🤯🤯🤯🤯🤯🤯🤯🤯🤯

(2)322. 零钱兑换 - 力扣(完全背包)--

class Solution {
public:int coinChange(vector<int>& coins, int amount) {//dp[i][j]:前i个coins凑成金额为j的最小硬币个数vector<vector<unsigned long long>> dp(coins.size(),vector<unsigned long long>(amount+1,INT_MAX ));for (int i = 0; i < coins.size(); i++) {dp[i][0] = 0;}// 处理第一种硬币的情况for (int j = coins[0]; j <= amount; j++) {if (j % coins[0] == 0) {dp[0][j] = j / coins[0];}}//dpfor(int i=1;i<coins.size();i++){for(int j=1;j<=amount;j++){if(coins[i]>j) dp[i][j]=dp[i-1][j];else{dp[i][j]=min(dp[i-1][j],dp[i][j-coins[i]]+1);}}}return (dp[coins.size()-1][amount]==INT_MAX)? -1:dp[coins.size()-1][amount];        }
};

dp 的第二维大小必须是 amount + 1,以便包含所有可能的金额从 0amount 

滚动数组优化~:

class Solution {
public:int coinChange(vector<int>& coins, int amount) {vector<int> dp(amount+1,INT_MAX-1);//避免 INT_MAX + 1 溢出dp[0]=0;// 金额 0 需要 0 枚硬币//dpfor(int i=0;i<coins.size();i++){for(int j=coins[i];j<=amount;j++){dp[j]=min(dp[j],dp[j-coins[i]]+1);}}return dp[amount]==INT_MAX-1?-1:dp[amount];}};

(3)518. 零钱兑换 II - 力扣(完全背包)-和25-3-2的csp题基本一样

类似这种题目:给出一个总数,一些物品,问能否凑成这个总数。(1--3题都是这样的)

这是典型的背包问题!但本题和纯完全背包不一样,纯完全背包是凑成背包最大价值是多少,而本题是要求凑成总金额的物品组合个数

因为每一种面额的硬币有无限个,所以这是完全背包(laoz当时咋就没想到,,)

这里注意初始化问题:

  •   当金额为0时,无论使用多少种硬币,只有一种组合方式,即不选择任何硬币,因此 所有的dp[i][0] = 1

  • 对于第一种硬币(i=0),只有当金额是其倍数时,组合数为1,否则为0。

    dp[0][j] = (j % coins[0] == 0) ? 1 : 0

遍历顺序:

        因为纯完全背包求得装满背包的最大价值是多少,和凑成总和的元素有没有顺序没关系,即:有顺序也行,没有顺序也行!

而本题要求凑成总和的组合数,元素之间明确要求没有顺序。所以纯完全背包是能凑成总和就行,不用管怎么凑的。

【本题是求组合数,所以先遍历物品再遍历背包容量】

然后就是完全背包的模版啦(注意开unsigend long long)

class Solution {
public:int change(int amount, vector<int>& coins) {// dp[i][j]:从前i个coin中选能够凑满j(包括j)这么大容量的包,有dp[i][j]种组合方法。vector<vector<int>> dp(coins.size(),vector<int>(amount+1,0));// 初始化:金额为0时组合数为1for (int i = 0; i < coins.size(); ++i) {dp[i][0] = 1;}// 处理第一种硬币的情况for (int j = 1; j <= amount; ++j) {dp[0][j] = (j % coins[0] == 0) ? 1 : 0;}//dpfor(int i=1;i<coins.size();i++)//遍历物品{for(int j=1;j<=amount;j++)//遍历容量{if(coins[i]>j) dp[i][j]=dp[i-1][j];else dp[i][j]=dp[i-1][j]+dp[i][j-coins[i]];}}return dp[coins.size()-1][amount];}
};

​ 数组开小了~~

滚动数组优化+扩宽存储范围:

class Solution {
public:int change(int amount, vector<int>& coins) {vector<unsigned long long> dp(amount+1,0);dp[0]=1;//dpfor(int i=0;i<coins.size();i++){for(int j=coins[i];j<=amount;j++){dp[j]=dp[j]+dp[j-coins[i]];}}return dp[amount];}};

(4)377. 组合总和 Ⅳ - 力扣(LeetCode) --完全背包

(2)要求最少硬币数量,要求硬币是组合数还是排列数都无所谓!所以两个for循环先后顺序怎样都可以! (3)是求硬币凑出来的方案个数,每个方案个数是组合数,所以必须外层for循环遍历物品,内层for遍历背包;而(4)本题目描述说是求组合,但又说是可以元素相同顺序不同的组合算两个组合,其实就是求排列!(直接记住滚动数组优化后的模版!!!

class Solution {
public:int combinationSum4(vector<int>& nums, int target) {// dp[j] 表示组成和为j的排列总数vector<int> dp(target + 1, 0);// 初始化:和为0的排列只有1种(空集)dp[0] = 1;// 外层循环遍历所有可能的目标和(背包容量)for (int j = 0; j <= target; j++) { // 内层循环遍历所有数字(物品)for (int i = 0; i < nums.size(); i++) { // 当目标和>=当前数字时,可以进行状态转移if (j >= nums[i]) {/* 状态转移方程:当前和为j的排列数 = 已计算的排列数 + 使用当前数字前的排列数(j - nums[i]时的排列数)例如:当nums[i]=2,j=5时dp[5] += dp[3] 表示所有和为3的排列末尾加上2的情况这体现了排列顺序不同视为独立解的特性*/dp[j] += dp[j - nums[i]];}}}return dp[target];}
};

 有两个测试用例相加超过Int的范围,所以开大一点:

class Solution {
public:int combinationSum4(vector<int>& nums, int target) {// dp[j] 表示组成和为j的排列总数vector<unsigned long long> dp(target + 1, 0);// 初始化:和为0的排列只有1种(空集)dp[0] = 1;// 外层循环遍历所有可能的目标和(背包容量)for (int j = 0; j <= target; j++) { // 内层循环遍历所有数字(物品)for (int i = 0; i < nums.size(); i++) { // 当目标和>=当前数字时,可以进行状态转移if (j >= nums[i]) {/* 状态转移方程:当前和为j的排列数 = 已计算的排列数 + 使用当前数字前的排列数(j - nums[i]时的排列数)例如:当nums[i]=2,j=5时dp[5] += dp[3] 表示所有和为3的排列末尾加上2的情况这体现了排列顺序不同视为独立解的特性*/dp[j] += dp[j - nums[i]];}}}return dp[target];}
};

(5)57. 爬楼梯 (卡玛)

很明显是求排列数,允许顺序不同~~直接套末班

 一遍AC~~~开心

#include<bits/stdc++.h>
using namespace std;
const int N=35;
int dp[N];
int n,m;
int main()
{cin>>n>>m;//m为物品 n为背包容量dp[0]=1;for(int j=1;j<=n;j++){for(int i=1;i<=m;i++){dp[j]+=dp[j-i];}}cout<<dp[n];return 0;
}

 🤯🤯🤯🤯🤯🤯🤯🤯🤯

(6)46. 携带研究材料(0-1背包)【 给定背包容量 装满背包 的最大价值是多少】

//纯模版 和0-1背包没什么不同ok?
#include<bits/stdc++.h>
using namespace std;
const int N=5010;
int dp[N][N];
int weight[N],value[N];
int main()
{int m,n;cin>>m>>n;//输入所占空间for(int i=1;i<=m;i++) cin>>weight[i];for(int i=1;i<=m;i++) cin>>value[i];//dpfor(int i=1;i<=m;i++){for(int j=0;j<=n;j++){if(weight[i]>j) dp[i][j]=dp[i-1][j];elsedp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);}}cout<<dp[m][n];return 0;
}

 (7)最快洗车时间(0-1)背包 

        已发bolg        

        基于 0/1 背包思想 解决 洗车时间分配问题,不是完全的模版题,本质上是子集和问题【给定一个 正整数数组 nums 和一个目标值 target,判断是否可以从 nums 选择 若干个数(每个数最多选一次),使其和 恰好等于 target】每辆车的洗车时间类似于 物品的重量

    dp[i][j] 表示前 i 辆车是否可以凑出洗车时间 j

  • 不选当前车dp[i][j] = dp[i-1][j]

  • 选当前车(当前车时间 car[i]):dp[i][j] |= dp[i-1][j - car[i]](如果没有|会丢失一种情况,不能直接等于)

 (一维:  dp[j] 能否恰好放入总时间不超过 j 的任务,滚动数组优化,注意逆序遍历)

(8)474. 一和零 - 力扣 (0-1背包)【给定背包容量,装满背包最多有多少个物品】

        这题也有点难度,这个背包有两个维度,一个是m 一个是n,而不同长度的字符串就是不同大小的待装物品

本题中strs 数组里的元素就是物品,每个物品都是一个!这就是一个典型的01背包! 只不过物品的重量有了两个维度而已。

 dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dp[i][j]

        dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1)

知道这些代码就很好写啦【因为背包已经有两个维度了,所以我们直接使用滚动数组的模版,否则要建三维数组!!】

class Solution {
public:int findMaxForm(vector<string>& strs, int m, int n) {// 初始化dp数组,dp[i][j] 表示在最多有 i 个 '0' 和 j 个 '1' 的情况下,能够组成的最大子集大小vector<vector<int>> dp(m+1, vector<int>(n+1, 0));// 遍历每个字符串(物品)for(string str : strs) { int one_num = 0, zero_num = 0;// 统计当前字符串中的 '0' 和 '1' 的数量for(char c : str) {if(c == '0') zero_num++;else one_num++;}// 采用 **逆序遍历**,确保每个字符串只能被选择一次(类似 0/1 背包问题)for(int i = m; i >= zero_num; i--) { // 遍历 '0' 的背包容量for(int j = n; j >= one_num; j--) { // 遍历 '1' 的背包容量// 状态转移:当前选择该字符串后,取最大值dp[i][j] = max(dp[i][j], dp[i - zero_num][j - one_num] + 1);}}}// 返回能组成的最大子集大小return dp[m][n];}
};

(9)279. 完全平方数 -(完全背包) 

求求最小数,遍历顺序不重要

dp[j]:和为j的完全平方数的最少数量为dp[j]超简单,和零钱兑换的原理一样

class Solution {
public:int numSquares(int n) {vector<int> dp(n+1,INT_MAX);dp[0]=0;for(int i=1;i*i<=n;i++) //遍历物品{for(int j=i*i;j<=n;j++){dp[j]=min(dp[j],dp[j-i*i]+1);}}return  dp[n];}
};

🎯三、子序列LSCDP 【线性DP的一个分支】

“子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序”。

(1)895. 最长上升子序列 - AcWing题库

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

①dp[i]表示以nums[i]结尾的最长递增子序列的长度

②位置i的最长升序子序列等于  j从0到i-1各个位置的最长升序子序列 + 1 的最大值。

所以转移方程:if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1)

③初始化:每一个i,对应的dp[i](即最长递增子序列)起始大小至少都是1

比较简单~~~

【acwing】动态规划系列_acwing memset dp-CSDN博客  含有此题

(2)674. 最长连续递增序列 - 力扣(LeetCode)

自己写的,一遍AC!!!!!!!!!!

class Solution {
public:int findLengthOfLCIS(vector<int>& nums) {vector<int> dp(nums.size(),1);//dpfor(int i=1;i<nums.size();i++){if(nums[i-1]<nums[i])//连续记录dp[i]=max(dp[i],dp[i-1]+1);}//找最长的int res=0;for(auto it:dp){res=max(res,it);}return res;}
};

 (3)最长公共子序列 - acwing

【acwing】动态规划系列_acwing memset dp-CSDN博客

博客中有这道题

数组索引从1开始

dp[i][j]: a数组中以i结尾和b数组中以j结尾的最长公共子序列

a[i] 和b[j] 相等: dp[i][j]=dp[i-1][j-1]+1;

不相等:则选择去掉s1的一个字符或去掉s2的一个字符, 最大的公共子序列长度来自于去掉一个字符的情况,这里求max,dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

喝喝,一开始初始化的时候写的int dp ,应该是char dp!!!!!!

(4)1035. 不相交的线 - 力扣

 

题目看起来挺抽象的,其实转换以下题意就是:直线不能相交,说明在字符串nums1中 找到一个与字符串nums2相同的子序列,且这个子序列不能改变相对顺序,只要相对顺序不改变,连接相同数字的直线就不会相交。 所以!!本题说是求绘制的最大连线数,其实就是求两个字符串的最长公共子序列的长度!

        数组索引从0开始,dp 数组的大小是 (n + 1) × (m + 1),由于 dp 数组的大小是 (n + 1) × (m + 1)dp[n][m] 正好对应于 nums1nums2 的完整长度

        所以需要判断的是nums1[i-1]==nums2[j-1]

 

class Solution {
public:int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {int n = nums1.size();int m = nums2.size();// dp[i][j] 表示 nums1 的前 i-1 个元素和 nums2 的前 j-1 个元素的最长公共子序列长度vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));// 动态规划填表for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {if (nums1[i - 1] == nums2[j - 1]) {// 如果当前元素相等,则在之前的基础上加 1dp[i][j] = dp[i - 1][j - 1] + 1;} else {// 如果当前元素不相等,则取两种情况的最大值dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);}}}// 返回最终结果,即 nums1 和 nums2 的最长公共子序列长度return dp[n][m];}
};

(5)718. 最长重复子数组 - (最长连续公共子序列)

子数组,其实就是连续子序列。注意区分与最长公共子序列问题的求解差异

①dp数组的含义:dp[i][j] ----以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度为dp[i][j]  (注意是i-1,所以遍历的时候要从1开始)

②转移方程: 当A[i - 1] 和B[j - 1]相等的时候,dp[i][j] = dp[i - 1][j - 1] + 1

③初始化:根据dp[i][j]的定义,dp[i][0] 和dp[0][j]其实都是没有意义的,为了后续可以正常递推,dp[i][0] 和dp[0][j]均初始化为0

④遍历顺序:先遍历a还是b都行

⑤举例推导:

class Solution {
public:int findLength(vector<int>& nums1, vector<int>& nums2) {//定义dp数组int n=nums1.size();int m=nums2.size();vector<vector<int>> dp(n+1,vector<int>(m+1,0));int res=0;////dpfor(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(nums1[i-1]==nums2[j-1])dp[i][j]=dp[i-1][j-1]+1;res=max(res,dp[i][j]);}}return res;}
};

注意数组索引从0开始,第一遍写的时候没定义res记录最大值~~~~ 呜呜呜

滚动数组优化:

dp[i][j]都是由dp[i - 1][j - 1]推出。那么压缩为一维数组,也就是dp[j]都是由dp[j - 1]推出。

也就是相当于可以把上一层dp[i - 1][j]拷贝到下一层dp[i][j]来继续用。

class Solution {
public:int findLength(vector<int>& nums1, vector<int>& nums2) {//定义dp数组int n=nums1.size();int m=nums2.size();vector<int> dp(n+1,0);int res=0;////dpfor(int i=1;i<=n;i++){for(int j=m;j>0;j--){if(nums1[i-1]==nums2[j-1])dp[j]=dp[j-1]+1;else dp[j] = 0; // 注意这里不相等的时候要有赋0的操作res=max(res,dp[j]);}}return res;}
};

拓展: 

如果dp[i][j]为 以下标i为结尾的A,和以下标j 为结尾的B,最长重复子数组长度

     那么 第一行和第一列毕竟要进行初始化,如果nums1[i] 与 nums2[0] 相同的话,对应的 dp[i][0]就要初始为1, 因为此时最长重复子数组为1。 nums2[j] 与 nums1[0]相同的话,同理。

// 版本三
class Solution {
public:int findLength(vector<int>& nums1, vector<int>& nums2) {vector<vector<int>> dp (nums1.size() + 1, vector<int>(nums2.size() + 1, 0));int result = 0;// 要对第一行,第一列经行初始化for (int i = 0; i < nums1.size(); i++) if (nums1[i] == nums2[0]) dp[i][0] = 1;for (int j = 0; j < nums2.size(); j++) if (nums1[0] == nums2[j]) dp[0][j] = 1;for (int i = 0; i < nums1.size(); i++) {for (int j = 0; j < nums2.size(); j++) {if (nums1[i] == nums2[j] && i > 0 && j > 0) { // 防止 i-1 出现负数dp[i][j] = dp[i - 1][j - 1] + 1;}if (dp[i][j] > result) result = dp[i][j];}}return result;}
};

(6)53. 最大子数组和 - 力扣

①dp含义:dp[i]:包括下标i(以nums[i]为结尾)的最大连续子序列和为dp[i]

②转移方程:

dp[i]只有两个方向可以推出来:

  • dp[i - 1] + nums[i],即:nums[i]加入当前连续子序列和
  • nums[i],即:从头开始计算当前连续子序列和(没考虑到这种情况,因为是连续的!!!

一定是取最大的,所以dp[i] = max(dp[i - 1] + nums[i], nums[i]); 

③初始化:dp[0] = nums[0]

class Solution {
public:int maxSubArray(vector<int>& nums) {//找最大和的连续子数组if (nums.size() == 0) return 0;//dp[i][j]:以i-1结尾的连续子数组的和vector<int> dp(nums.size());dp[0]=nums[0];int res=dp[0];//dpfor(int i=1;i<nums.size();i++){dp[i]=max(nums[i],dp[i-1]+nums[i]);res=max(res,dp[i]);}return res;}
};

dp 的大小应该是 nums.size(),以便索引范围从 0nums.size() - 1 

 (7) 392. 判断子序列 - 力扣 

编辑距离的入门题目

dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]

if (s[i - 1] == t[j - 1]),那么dp[i][j] = dp[i - 1][j - 1] + 1

if (s[i - 1] != t[j - 1]),此时相当于t要删除元素 dp[i][j] = dp[i][j - 1]

最终判断dp[n][m]是否和 s子串的长度相等

【和 1143.最长公共子序列 (opens new window)的递推公式基本那就是一样的,区别就是 本题 如果删元素一定是字符串t,而最长公共子序列 是两个字符串都可以删元素。】

class Solution {
public:bool isSubsequence(string s, string t) {int n = s.length(); // 获取字符串 s 的长度int m = t.length(); // 获取字符串 t 的长度// dp[i][j] 以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));// 遍历字符串 s 和 tfor (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {if (s[i - 1] == t[j - 1]) {// 如果当前字符匹配,则最长公共子序列长度加 1dp[i][j] = dp[i - 1][j - 1] + 1;} else {// 如果当前字符不匹配,则取 t 的前 j-1 个字符与 s 的前 i 个字符的最长公共子序列长度// 因为 dp[i][j] 已经初始化为 0,所以这里可以直接赋值dp[i][j] = max(dp[i][j], dp[i][j - 1]);}}}// 如果 s 是 t 的子序列,则 dp[n][m] 应该等于 s 的长度 n// 因为 s 的所有字符都必须在 t 中按顺序出现if (dp[n][m] == n) return true;else return false;}
};

(8)拍照【最长山峰子序列】---已发博客,点击标题跳转

在这里总结一下,就是用两个dp,一个求最长上升子序列,一个求最长下降子序列(也就是倒序最长上升,改一下遍历顺序就可以啦)

dp1 (最长上升子序列):

dp2 (最长下降子序列):

最终结果(最少出队人数)是总长度(n)减去可以组成的最长序列的长度(dp1+dp2-1)

(9)72. 编辑距离 - 力扣

【acwing】动态规划系列_acwing memset dp-CSDN博客  ----最短编辑距离【同款题目】

①dp定义:dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]

②转移方程:

if (word1[i - 1] == word2[j - 1])不操作 dp[i][j] = dp[i - 1][j - 1]
if (word1[i - 1] != word2[j - 1])① 增
//word2添加一个元素,相当于word1删除一个元素② 删
//word1删除一个元素,那么就是以下标i - 2为结尾的word1 与 j-1为结尾的word2的最近编辑距离 再加上一个操作
dp[i][j] = dp[i - 1][j] + 1
//操作二:word2删除一个元素,那么就是以下标i - 1为结尾的word1 与 j-2为结尾的word2的最近编辑距离 再加上一个操作
dp[i][j] = dp[i][j - 1] + 1③ 换
//替换元素,word1替换word1[i - 1],使其与word2[j - 1]相同,此时不用增删加元素。if (word1[i - 1] == word2[j - 1])的时候我们的操作 是 dp[i][j] = dp[i - 1][j - 1] ,那么只需要一次替换的操作,就可以让 word1[i - 1] 和 word2[j - 1] 相同。所以 dp[i][j] = dp[i - 1][j - 1] + 1

综上,当 if (word1[i - 1] != word2[j - 1]) 时取最小的,即:dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1; 

③初始化:

dp[i][0] 和 dp[0][j] 表示什么呢?

        dp[i][0] :以下标i-1为结尾的字符串word1,和空字符串word2,最近编辑距离为dp[i][0]。

那么dp[i][0]就应该是i,对word1里的元素全部做删除操作,即:dp[i][0] = i;

同理dp[0][j] = j;

class Solution {
public:int minDistance(string s, string t) {//定义dp数组vector<vector<int>> dp(s.size()+1,vector<int>(t.size()+1,0));//初始化dp[i][0]  dp[0][j]for(int i=1;i<=s.size();i++) dp[i][0]=i;for(int j=1;j<=t.size();j++) dp[0][j]=j;//dpfor(int i=1;i<=s.size();i++){for(int j=1;j<=t.size();j++){if(s[i-1]==t[j-1])dp[i][j]=dp[i-1][j-1];elsedp[i][j]=min({dp[i-1][j-1],dp[i-1][j],dp[i][j-1]})+1;}}return dp[s.size()][t.size()];}
};

相关文章:

动态规划dp专题-(上)

目录 dp理论知识&#x1f525;&#x1f525; &#x1f3af;一、线性DP &#xff08;1&#xff09;&#x1f680;斐波那契数 -入门级 &#xff08;2&#xff09;&#x1f680;898. 数字三角形-acwing ---入门级 &#xff08;3&#xff09;往期题目 ①选数异或&#xff1a;在…...

正则表达式(一)

一、模式&#xff08;Patterns&#xff09;和修饰符&#xff08;flags&#xff09; 通过正则表达式&#xff0c;我们可以在文本中进行搜索和替换操作&#xff0c;也可以和字符串方法结合使用。 正则表达式 正则表达式&#xff08;可叫作 “regexp”&#xff0c;或 “reg”&…...

需求变更导致成本超支,如何止损

需求变更导致成本超支时&#xff0c;可以通过加强需求管理、严格的变更控制流程、优化资源配置、实施敏捷开发、提高风险管理意识等方法有效止损。其中&#xff0c;加强需求管理是止损的核心措施之一。需求管理涉及需求明确化、需求跟踪和变更的管理&#xff0c;有效的需求管理…...

《数据分析与可视化》(清华)ch5-实训代码

小费数据集预处理——求思考题_有问必答-CSDN问答 以上代码在Jupyter Notebook中可以运行&#xff0c;但是在python中就会出如下问题&#xff1a; 这个错误表明在尝试计算均值填充缺失值时&#xff0c;数据中包含非数值类型的列&#xff08;如文本列&#xff09;&#xff0c;…...

E: The package APP needs to be reinstalled, but I can‘t find an archive for it.

要解决错误 “E: The package mytest needs to be reinstalled, but I can’t find an archive for it”&#xff0c;通常是因为系统中存在损坏的软件包记录或安装过程中断导致 /var/lib/dpkg/status 文件异常。以下是综合多篇搜索结果的解决方案&#xff1a; 解决步骤 备份关…...

若依startPage()详解

背景 startPage基于PageHelper来进行强化&#xff0c;在用户传入pagesize,pageNum等标准参数的时候不需要进行解析 步骤 1.通过ServletUtils工具类getRequestAttributes来获取当前线程的上下文信息 public static ServletRequestAttributes getRequestAttributes() {try {R…...

Oracle AQ

Oracle AQ&#xff08;Advanced Queuing&#xff09; 是 Oracle 数据库内置的一种消息队列&#xff08;Message Queue&#xff09;技术&#xff0c;用于在应用或系统之间实现异步通信、可靠的消息传递和事件驱动架构。它是 Oracle 数据库的核心功能之一&#xff0c;无需依赖外部…...

npm报错CERT_HAS_EXPIRED解决方案

npm报错解决方案 npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED方案1:尝试切换镜像 # 使用腾讯云镜像 npm config set registry https://mirrors.cloud.tencent.com/npm/# 或使用官方npm源&#xff08;科学上网&#xff09; npm config set registry http…...

pnpm 中 Next.js 模块无法找到问题解决

问题概述 项目在使用 pnpm 管理依赖时,出现了 “Cannot find module ‘next/link’ or its corresponding type declarations” 的错误。这是因为 pnpm 的软链接机制在某些情况下可能导致模块路径解析问题。 问题诊断 通过命令 pnpm list next 确认项目已安装 Next.js 15.2.…...

急速实现Anaconda/Miniforge虚拟环境的克隆和迁移

目录 参考资料 点击Anaconda Prompt (anaconda_base) 查看现有环境 开始克隆&#xff0c;以克隆pandas_env为例&#xff0c;新的环境名字为image (base) C:\Users\hello>conda create -n image --clone pandas_env查看克隆结果&#xff0c;image环境赫然在列。 然后粘贴…...

OpenCv高阶(二)——图像的掩膜

目录 掩膜 bitwise_and原理 掩膜的实现 1、基于像素操作 2、使用形态学操作 3、基于阈值处理 案例 1、读取原图并绘制掩膜 2、掩膜的实现 3、绘制掩膜的直方图 应用 掩膜 OpenCV 中图像掩膜&#xff08;Mask&#xff09;实现的原理是通过一个与原始图像大小相同的二…...

数据结构和算法(十二)--最小生成树

一、最小生成树 定义&#xff1a;图的生成树是它的一颗含有其所有顶点的无环连通子图&#xff0c;一副加权无向图的最小生成树它的一颗权值&#xff08;树中所有边的权重之和&#xff09;最小的生成树。 约定&#xff1a;只考虑连通图。最小生成树的定义说明它只能存在于连通图…...

开源酷炫的Linux监控工具:sampler

sampler是一个开源的监控工具&#xff0c;来自GitHub用户sqshq&#xff08;Alexander Lukyanchikov&#xff09;的匠心之作。 简单来说&#xff0c;sampler能干这些事儿&#xff1a; 实时监控&#xff1a;CPU、内存、磁盘、网络&#xff0c;甚至应用程序的状态&#xff0c;它…...

InternVideo2.5:Empowering Video MLLMs with Long and Rich Context Modeling

一、TL&#xff1b;DR InternVideo2.5通过LRC建模来提升MLLM的性能。层次化token压缩和任务偏好优化&#xff08;mask时空 head&#xff09;整合到一个框架中&#xff0c;并通过自适应层次化token压缩来开发紧凑的时空表征MVBench/Perception Test/EgoSchema/MLVU数据benchmar…...

OSPF基础与特性

一.OSPF 的技术背景 OSPF出现是因为RIP协议无法满足大型网络的配置 RIP协议中存在的问题 RIP中存在最大跳数为15的限制,不能适应大规模组网 RIP周期性发送全部路由信息,占用大量的带宽资源 路由收敛速度慢 以跳数作为度量衡,选路可能会不优 存在路由环路的可能性 每隔30秒更新…...

[Linux]从零开始的ARM Linux交叉编译与.so文件链接教程

一、前言 最近在项目需要将C版本的opencv集成到原本的代码中从而进行一些简单的图像处理。但是在这其中遇到了一些问题&#xff0c;首先就是原本的opencv我们需要在x86的架构上进行编译然后将其集成到我们的项目中&#xff0c;这里我们到底应该将opencv编译为x86架构的还是编译…...

golang 中 make 和 new 的区别?

在Go语言中&#xff0c;make 和 new 都是用于内存分配的关键字&#xff0c;但它们在使用场景、返回值和初始化方式等方面存在一些区别&#xff0c;以下是具体分析&#xff1a; 使用场景 make 只能用于创建 map、slice 和 channel 这三种引用类型&#xff0c;用于初始化这些类型…...

碧螺春是绿茶还是红茶

碧螺春是绿茶&#xff0c;不是红茶。 碧螺春的特点&#xff1a; 类别: 碧螺春属于中国六大茶类中的绿茶类。产地: 它产自中国江苏省苏州市太湖的东山和西山&#xff08;现称金庭镇&#xff09;&#xff0c;是中国十大名茶之一。外形: 碧螺春茶叶外形卷曲如螺&#xff0c;色泽…...

Linux平台搭建MQTT测试环境

Paho MQTT Paho MQTT‌ 是 Eclipse 基金会下的一个开源项目&#xff0c;旨在为多种编程语言提供 ‌MQTT 协议‌的客户端实现。MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的发布/订阅&#xff08;Pub/Sub&#xff09;消息传输协议&#xff…...

【AI学习】AI Agent(人工智能体)

1&#xff0c;AI agent 1&#xff09;定义 是一种能够感知环境、基于所感知到的信息进行推理和决策&#xff0c;并通过执行相应动作来影响环境、进而实现特定目标的智能实体。 它整合了多种人工智能技术&#xff0c;具备自主学习、自主行动以及与外界交互的能力&#xff0c;旨…...

克魔助手(Kemob)安装与注册完整教程 - Windows/macOS双平台指南

iOS设备管理工具克魔助手便携版使用全指南 前言&#xff1a;为什么需要专业的iOS管理工具 在iOS开发和设备管理过程中&#xff0c;开发者经常需要突破系统限制&#xff0c;实现更深层次的控制和调试。本文将详细介绍一款实用的便携式工具的使用方法&#xff0c;帮助开发者快速…...

了解GPIO对应的主要功能

GPIO GPIO是通用输入输出端口的简称&#xff0c;芯片上的GPIO引脚与外部设备连接实现通讯、控制以及数据采集等功能&#xff0c;最基本的输出功能是通过控制引脚输出高低电平继而实现开关控制&#xff0c;比如引脚接入LED灯可控制LED灯的亮灭&#xff0c;接入继电器或三极管可…...

Dubbo 注册中心与服务发现

注册中心与服务发现 注册中心概述 注册中心是dubbo服务治理的核心组件&#xff0c;Dubbo依赖注册中心的协调实现服务发现&#xff0c;自动化的服务发现是微服务实现动态扩容、负载均衡、流量治理的基础。 Dubbo的服务发现机制经历了Dubbo2时代的接口级服务发现、Dubbo3时代的…...

一文详解LibTorch环境搭建:Ubuntu20.4配置LibTorch CUDA与cuDNN开发环境

随着深度学习技术的迅猛发展&#xff0c;越来越多的应用程序开始集成深度学习模型以提供智能化服务。为了满足这一需求&#xff0c;开发者们不仅依赖于Python等高级编程语言提供的便捷框架&#xff0c;也开始探索如何将这些模型与C应用程序相结合&#xff0c;以便在性能关键型应…...

micro ubuntu 安装教程

micro ubuntu 安装教程 官网地址 : https://micro-editor.github.io 以下是在 Ubuntu 系统中安装 micro 编辑器 的详细教程&#xff1a; 方法 1&#xff1a;通过 ​apt​​ 直接安装&#xff08;推荐&#xff09; 适用于 Ubuntu 20.04 及以上版本&#xff08;官方仓库已收录…...

观成科技:利用DoH加密信道的C2流量分析

概述 DoH&#xff08;DNS over HTTPS&#xff09;是一种通过HTTPS协议加密传输DNS查询的信道&#xff0c;将DNS请求封装在HTTP/2或HTTP/3中&#xff0c;DoH没有标准端口&#xff0c;部分服务沿用TLS的443端口。传统DNS明文传输易被拦截或篡改&#xff0c;而DoH通过加密提升了隐…...

行星际空间的磁流体动力激波:理论综述

Magnetohydrodynamic Shocks in the Interplanetary Space: a Theoretical Review ( Part 2 ) ​​​​​​​Magnetohydrodynamic Shocks in the Interplanetary Space: a Theoretical Review | Brazilian Journal of Physics Magnetohydrodynamic Shocks 1. The Rankine-Hu…...

Java垃圾回收的隐性杀手:过早晋升的识别与优化实战

目录 一、现象与症状 二、过早晋升的成因 &#xff08;一&#xff09;Young区&#xff08;Eden区&#xff09;配置过小 &#xff08;二&#xff09;分配速率过高 &#xff08;三&#xff09;晋升年龄阈值&#xff08;MaxTenuringThreshold&#xff09;配置不当 三、动态晋…...

2noise团队开源ChatTTS,支持多语言、流式合成、语音的情感、停顿和语调控制

简介 ChatTTS 是一个开源的文本转语音&#xff08;Text-to-Speech, TTS&#xff09;项目&#xff0c;由 2noise 团队开发&#xff0c;专门为对话场景设计。它在 GitHub 上广受欢迎&#xff0c;因其自然流畅的语音合成能力和多功能性而备受关注。 项目背景 目标&#xff1a;设计…...

企业级防火墙与NAT网关配置

实训背景 某公司需部署一台Linux网关服务器&#xff0c;要求实现以下功能&#xff1a; 基础防火墙&#xff1a;仅允许SSH&#xff08;22&#xff09;、HTTP&#xff08;80&#xff09;、HTTPS&#xff08;443&#xff09;入站&#xff0c;拒绝其他所有流量。共享上网&#xf…...

AI数据分析的正道是AI+BI,而不是ChatBI

一、AI大模型在数据分析中的应用现状与局限 当前用户直接上传PDF、Excel等原始数据至AI大模型进行自动分析的趋势显著&#xff0c;但其技术成熟度与落地效果仍需审慎评估。 1.主流AI大模型的数据分析能力对比 GPT-4/Claude 3系列&#xff1a;在通用数据分析任务中表现突出&a…...

C++设计模式优化实战:提升项目性能与效率

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开发技术&#xff0c;能熟练应用常用数据库SQL server,Oracle…...

G1学习打卡

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 import argparse import os import numpy as np import torchvision.transforms as transforms from torchvision.utils import save_image from torch.utils.…...

8.2 对话框2

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的 8.2.3 FolderBrowserDialog&#xff08;文件夹对话框&#xff09; 组件 FolderBrowserDialog组件&#xff0c;用于选择文件夹 Folder…...

Java中的列表(List):操作与实现详解

引言 列表&#xff08;List&#xff09;是Java集合框架中最基础且使用最频繁的线性数据结构。它允许有序存储元素&#xff0c;支持重复值和快速访问。本文将深入探讨Java列表的核心操作方法&#xff0c;并剖析两种经典实现类&#xff08;ArrayList和LinkedList&#xff09;的底…...

在kotlin的安卓项目中使用dagger

在 Kotlin 的 Android 项目中使用 ​​Dagger​​&#xff08;特别是 ​​Dagger Hilt​​&#xff0c;官方推荐的简化版&#xff09;进行依赖注入&#xff08;DI&#xff09;可以大幅提升代码的可测试性和模块化程度。 1. 配置 Dagger Hilt​​ ​​1.1 添加依赖​​ 在 bu…...

MongoDB常见面试题总结(上)

MongoDB 基础 MongoDB 是什么&#xff1f; MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统&#xff0c;由 C 编写的。MongoDB 提供了 面向文档 的存储方式&#xff0c;操作起来比较简单和容易&#xff0c;支持“无模式”的数据建模&#xff0c;可以存储比较复杂…...

leetcode6.Z字形变换

题目说是z字形变化&#xff0c;但其实模拟更像n字形变化&#xff0c;找到字符下标规律就逐个拼接就能得到答案 class Solution {public String convert(String s, int numRows) {if(numRows1)return s;StringBuilder stringBuilder new StringBuilder();for (int i 0; i <…...

VSCode中选择Anaconda的Python环境

1、安装Anaconda 2、安装VSCode 一、创建创建新的 Conda 环境 conda create --name myenv python3.8 conda activate myenv 二、在 VSCode 中配置 Conda 环境 1、打开 VSCode&#xff0c;安装 Python 插件。 2、按 CtrlShiftP 打开命令面板&#xff0c;输入并选择 Pytho…...

【基于规则】基于距离的相似性度量

基于点:设时两条序曲线分别为X,Y,在曲线上选取点Xx和Yy,计算点之间的距离,用来度量两条曲线的相似性。这类算法的精确度取决于选点的规则,以及距离的计算方式 欧几里得距离:不允许时间偏移,直接计算两个时序数据点之间的距离,适用于长度相同的序列 dtw:优化了选点的方…...

Python 序列构成的数组(当列表不是首选时)

当列表不是首选时 虽然列表既灵活又简单&#xff0c;但面对各类需求时&#xff0c;我们可能会有更好的选 择。比如&#xff0c;要存放 1000 万个浮点数的话&#xff0c;数组&#xff08;array&#xff09;的效率要高 得多&#xff0c;因为数组在背后存的并不是 float 对象&…...

LeetCode零钱兑换(动态规划)

题目描述 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额&#xff0c;返回 -1 。 你可以认为每种硬币的数量是无…...

vscode+wsl 运行编译 c++

linux 的 windows 子系统&#xff08;wsl&#xff09;是 windows 的一项功能&#xff0c;可以安装 Linux 的发行版&#xff0c;例如&#xff08;Ubuntu&#xff0c;Kali&#xff0c;Arch Linux&#xff09;等&#xff0c;从而可以直接在 windows 下使用 Linux 应用程序&#xf…...

C++学习之libevent ②

目录 1.连接服务器函数bufferevent_socket_connect() 2.bufferevent缓冲区的读写函数bufferevent_write() bufferevent_read() 3.给bufferevent设置回调函数bufferevent_setcb&#xff08;&#xff09; 4.bufferevent回调函数的函数原型 5.基于bufferevent的套接字客户端处…...

彩色路径 第32次CCF-CSP计算机软件能力认证

应该用dp做的但是我太懒懒得看题解了 留到考试的时候看 超时20分代码&#xff1a; #include<bits/stdc.h> using namespace std; int N, M, L, K; struct Edge {int to, length;Edge(int to, int length) :to(to), length(length) {} }; vector<int> color;//颜色…...

第1章 绪论

自1946年&#xff0c;第一台计算机问世以来&#xff0c;计算机产业飞速发展。为了编写出一个好得程序&#xff0c;必须分析待处理的对象的特征以及各处理对象之间存在的关系。这就是数据结构这门学科形成和发展的背景。 1.1什么是数据结构 数据结构是计算机科学中组织和存储数…...

SpringCloud微服务(一)Eureka+Nacos

一、认识 微服务技术对比&#xff1a; SpringCloud&#xff1a; 版本匹配&#xff1a; 二、服务拆分以及远程调用 消费者与提供者&#xff1a; Eureka&#xff1a; 搭建EurekaServer&#xff1a; Ribbon负载均衡&#xff1a; 实现原理&#xff1a; IRule&#xff1a;规则接口…...

Python 字典和集合(子类化UserDict)

本章内容的大纲如下&#xff1a; 常见的字典方法 如何处理查找不到的键 标准库中 dict 类型的变种set 和 frozenset 类型 散列表的工作原理 散列表带来的潜在影响&#xff08;什么样的数据类型可作为键、不可预知的 顺序&#xff0c;等等&#xff09; 子类化UserDict 就创造自…...

时区转换工具+PWA离线网页

时区转换工具PWA离线网页 一、时区转换工具对比 工具说明Date原生 JS API&#xff0c;有限的时区支持&#xff0c;无法指定时区&#xff0c;仅使用本地时区。Intl.DateTimeFormat原生格式化显示&#xff0c;可指定时区&#xff0c;但不能修改时区逻辑。luxon强烈推荐&#xf…...

Hadoop序列化与反序列化具体实践

首先创建两个类 两个类的代码 Student类&#xff1a; import org.apache.hadoop.io.Writable;import java.io.DataInput; import java.io.DataOutput; import java.io.IOException;public class Student implements Writable {public Student(String name, int age) {this.n…...