feat: 动态规划子序列问题

This commit is contained in:
LouisFonda 2025-05-22 17:16:44 +08:00
parent 11b04202d8
commit a5e958c203
Signed by: yigencong
GPG Key ID: 29CE877CED00E966
7 changed files with 275 additions and 0 deletions

View File

@ -0,0 +1,31 @@
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number}
*/
const maxUncrossedLines = function (nums1, nums2) {
};
/*
这个题看似无从下手实际上非常得简单我们从结果入手一个不交叉得最大连线是什么样的经过观察发现就是要我们求
最大公共序列直接把1143的题目拿过来改一下即可
*/
function f1(nums1, nums2) {
const m = nums1.length;
const n = nums2.length;
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
for (let i = m - 1; i >= 0; i--) {
for (let j = n - 1; j >= 0; j--) {
if (nums1[i] === nums2[j]) {
dp[i][j] = dp[i + 1][j + 1] + 1;
} else {
dp[i][j] = Math.max(dp[i + 1][j], dp[i][j + 1]);
}
}
}
return dp[0][0];
}

View File

@ -0,0 +1,30 @@
/**
* @param {string} text1
* @param {string} text2
* @return {number}
*/
const longestCommonSubsequence = function (text1, text2) {
};
/*
定义dp[i][j]为text1从i位置开始统计text2从j位置开始统计的最长公共子序列长度如果text1[i]和text2[j]相等则dp[i][j]=dp[i+1][j+1]
若不相等则dp[i][j] = max(dp[i+1][j], dp[i][j+1])
*/
function f1(text1, text2) {
const m = text1.length;
const n = text2.length;
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
for (let i = m - 1; i >= 0; i--) {
for (let j = n - 1; j >= 0; j--) {
if (text1[i] === text2[j]) {
dp[i][j] = dp[i + 1][j + 1] + 1;
} else {
dp[i][j] = Math.max(dp[i + 1][j], dp[i][j + 1]);
}
}
}
return dp[0][0];
}

View File

@ -0,0 +1,30 @@
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
const isSubsequence = function (s, t) {
return f1(s, t);
};
/*
这个题目起始从头到尾遍历开s[1]在不在t中然后再看s[2]在不在最后看s[len - 1]在不在如果在则返回true,
这个题目也可以是使用动态规划动态规划的思路就是如果s[i]在t中存在如果s[i+1:]这个子序列也在t中存在,
那么s[i:]开始的子序列在t中也存在定义dp[i]字符串s从i开始的所有子序列s[i:]在t[j]之后的子序列中存在
s[i] === t[j]
*/
function f2(s, t) {
if (s.length === 0) return true;
if (t.length === 0) return false;
const dp = Array(s.length).fill(false);
for (let j = t.length - 1, i = s.length - 1; j >= 0 && i >= 0; j--) {
if (t[j] === s[i]) {
dp[i] = true;
i--;
}
}
return dp[0];
}

View File

@ -0,0 +1,27 @@
/**
* @param {number[]} nums
* @return {number}
*/
const maxSubArray = function (nums) {
};
/*
定义dp[i]为从nums[i]开始的和最大的子数组那么动态转移方程为dp[i] = dp[i+1] + nums[i] (dp[i+1] > 0)
*/
function f1(nums) {
const dp = Array(nums.length + 1).fill(0); // dp[i]表示从i位置开始的和最大子数组
let result = -Infinity;
for (let i = nums.length - 1; i >= 0; i--) {
if (dp[i + 1] > 0) {
dp[i] = nums[i] + dp[i + 1];
} else {
dp[i] = nums[i];
}
result = Math.max(result, dp[i]);
}
return result;
}

View File

@ -0,0 +1,72 @@
/**
* @param {string} word1
* @param {string} word2
* @return {number}
*/
const minDistance = function (word1, word2) {
};
/*
这个题看似无从下手其实反过来思考非常容易直接求出最长的公共子序列然后步数就是这个两个字符串中多出的那几个字符的和
*/
function f1(word1, word2) {
const commonLen = longestCommonSubsequence(word1, word2);
return word1.length + word2.length - 2 * commonLen;
}
function longestCommonSubsequence(text1, text2) {
const m = text1.length;
const n = text2.length;
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
for (let i = m - 1; i >= 0; i--) {
for (let j = n - 1; j >= 0; j--) {
if (text1[i] === text2[j]) {
dp[i][j] = dp[i + 1][j + 1] + 1;
} else {
dp[i][j] = Math.max(dp[i + 1][j], dp[i][j + 1]);
}
}
}
return dp[0][0];
}
/*
直接利用动态规划来求解定义dp[i][j]为s1中前i个字符和s2中前j个字符变得相同需要删除的字符数量的最少个数第i个字符是s1[i-1]
同理第j个字符是s2[j-1]注意这里的dp[i][j]的定义是前i个字符从1开始数的之所以要这样定义是因为s1可以为空字符需要使用dp[0][0]
来表示空字符
*/
function f2(word1, word2) {
const m = word1.length;
const n = word2.length;
// 定义dp表m+1行n+1列
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); // 初始化成0没有特殊意义反正都要填表
// 初始第一行s1为空字符串那么当s2有多少个字符就取出多少个即dp[0][j] = j
for (let j = 0; j <= n; j++) {
dp[0][j] = j;
}
// 列同理
for (let i = 0; i <= m; i++) {
dp[i][0] = i;
}
// 填充dp表从上到下从左到右
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (word1[i - 1] === word2[j - 1]) { // 如果第i个字符和第j个字符相等
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + 1;
}
}
}
return dp[m][n];
}

View File

@ -0,0 +1,37 @@
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number}
*/
const findLength = function (nums1, nums2) {
};
/*
定义dp[i][j]表示nums1从i开始nums2从j开始的最长子数组的长度dp[i][j]可以由两种情况得来第一种当nums1[i] !== nums2[j],
那么从这个位置开始的子数组就不可能是公共子数组多以dp[i][j] = 0;第二种当nums1[i] === nums2[j] 那么dp[i][j] = 1 + dp[i+1][j+1]
得来
*/
function f1(nums1, nums2) {
const m = nums1.length;
const n = nums2.length;
let result = 0;
// 定义dp表并且初始化
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
// 按照dp[i][j]的定义我们需要从下到上从右到左填充dp数组
for (let i = m - 1; i >= 0; i--) {
for (let j = n - 1; j >= 0; j--) {
if (nums1[i] === nums2[j]) {
dp[i][j] = 1 + dp[i + 1][j + 1];
result = Math.max(result, dp[i][j]);
} else {
dp[i][j] = 0;
}
}
}
console.log(dp);
return result;
}
f1([0, 0, 0, 0, 1], [0, 0, 0, 0, 1]);

View File

@ -0,0 +1,48 @@
/**
* @param {string} word1
* @param {string} word2
* @return {number}
*/
const minDistance = function (word1, word2) {
};
/*
有删除添加修改三种操作word1的删除和word2的添加效果是一样的所以实际上只有三种操作
1. 往word1中删除一个字符
2. 往word2中删除一个字符
3. 修改word1中的一个字符
定义dp[i][j]表示word1的前i个字符和word2的前j个字符的最少编辑距离那么在已知dp[i-1][j-1]和dp[i-1][j],dp[i][j-1]的情况下推出来
如果第word1的第i个字符和word2的第j个字符相等那么最小编辑距离就是dp[i-1][j-1]因为第i个数和第j个字符我不需要操作而剩下的这些字符
最少编辑距离就是dp[i-1][j-1],如果这word1的第i个字符和word2的第j个字符不相等我们可以删除word1的第i个字符然后将word1的前i-1个字符
和word2的前j个字符变得一样所需得编辑距离加上删除word1得第i个字符这一步一共是dp[i-1][j] + 1个编辑距离同理dp[i][j-1]得原理一样
最后还有一种获得最优得情况是我不删除只是将word1中得最后一个字符修改成和word2中卒子后一个字符一样这样就变成word1[i-1]==word2[j-1]
相等得情况了
*/
function f1(word1, word2) {
const m = word1.length;
const n = word2.length;
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); // 初始化成0无意义只是初始化而已
// 初始化如果word1为空word2要想变得和word1一样编辑距离就是它自身长度
for (let j = 0; j <= n; j++) {
dp[0][j] = j;
}
// word2为空同理
for (let i = 0; i <= m; i++) {
dp[i][0] = i;
}
// 填dp表,dp[i][j] 依赖dp[i-1][j-1], dp[i-1][j], dp[i][j-1],所以要从上到下,从左到右遍历
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (word1[i - 1] === word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1;
}
}
}
return dp[m][n];
}