diff --git a/leetcode-docs/hard/10-is-match.mdx b/leetcode-docs/hard/10-is-match.mdx index c8008a93..80a21653 100644 --- a/leetcode-docs/hard/10-is-match.mdx +++ b/leetcode-docs/hard/10-is-match.mdx @@ -14,6 +14,7 @@ keywords: - [44. 通配符匹配](/leetcode/hard/44-is-match) - [72. 编辑距离](/leetcode/hard/72-min-distance) - [115. 不同的子序列](/leetcode/hard/115-num-distinct) +- [516. 最长回文子序列](/leetcode/medium/516-longest-palindrome-subseq) - [583. 两个字符串的删除操作](/leetcode/medium/583-min-distance) - [1143. 最长公共子序列](/leetcode/medium/1143-longest-common-subsequence) diff --git a/leetcode-docs/hard/115-num-distinct.mdx b/leetcode-docs/hard/115-num-distinct.mdx index 20633ccb..09a4abc4 100644 --- a/leetcode-docs/hard/115-num-distinct.mdx +++ b/leetcode-docs/hard/115-num-distinct.mdx @@ -14,6 +14,7 @@ keywords: - [10. 正则表达式匹配](/leetcode/hard/10-is-match) - [44. 通配符匹配](/leetcode/hard/44-is-match) - [72. 编辑距离](/leetcode/hard/72-min-distance) +- [516. 最长回文子序列](/leetcode/medium/516-longest-palindrome-subseq) - [583. 两个字符串的删除操作](/leetcode/medium/583-min-distance) - [1143. 最长公共子序列](/leetcode/medium/1143-longest-common-subsequence) diff --git a/leetcode-docs/hard/44-is-match.mdx b/leetcode-docs/hard/44-is-match.mdx index ed5f0ab0..3f9c3d34 100644 --- a/leetcode-docs/hard/44-is-match.mdx +++ b/leetcode-docs/hard/44-is-match.mdx @@ -14,6 +14,7 @@ keywords: - [10. 正则表达式匹配](/leetcode/hard/10-is-match) - [72. 编辑距离](/leetcode/hard/72-min-distance) - [115. 不同的子序列](/leetcode/hard/115-num-distinct) +- [516. 最长回文子序列](/leetcode/medium/516-longest-palindrome-subseq) - [583. 两个字符串的删除操作](/leetcode/medium/583-min-distance) - [1143. 最长公共子序列](/leetcode/medium/1143-longest-common-subsequence) diff --git a/leetcode-docs/hard/72-min-distance.mdx b/leetcode-docs/hard/72-min-distance.mdx index 5402a639..4e75246a 100644 --- a/leetcode-docs/hard/72-min-distance.mdx +++ b/leetcode-docs/hard/72-min-distance.mdx @@ -14,6 +14,7 @@ keywords: - [10. 正则表达式匹配](/leetcode/hard/10-is-match) - [44. 通配符匹配](/leetcode/hard/44-is-match) - [115. 不同的子序列](/leetcode/hard/115-num-distinct) +- [516. 最长回文子序列](/leetcode/medium/516-longest-palindrome-subseq) - [583. 两个字符串的删除操作](/leetcode/medium/583-min-distance) - [1143. 最长公共子序列](/leetcode/medium/1143-longest-common-subsequence) diff --git a/leetcode-docs/medium/1143-longest-common-subsequence.mdx b/leetcode-docs/medium/1143-longest-common-subsequence.mdx index fae0b76d..71a79c71 100644 --- a/leetcode-docs/medium/1143-longest-common-subsequence.mdx +++ b/leetcode-docs/medium/1143-longest-common-subsequence.mdx @@ -15,6 +15,7 @@ keywords: - [44. 通配符匹配](/leetcode/hard/44-is-match) - [72. 编辑距离](/leetcode/hard/72-min-distance) - [115. 不同的子序列](/leetcode/hard/115-num-distinct) +- [516. 最长回文子序列](/leetcode/medium/516-longest-palindrome-subseq) - [583. 两个字符串的删除操作](/leetcode/medium/583-min-distance) ::: @@ -66,7 +67,7 @@ keywords: 一般要构造如下 `dp` 二维数组, 即让 `dp[0][0]` 为 `0`. 那么从索引 `1` 开始, `dp[i][j]` 的含义就是: `s1[1..i]` 和 `s2[1..j]`, 它们的最长公共子序列是 `dp[i][j]`. -对于下面这个例子, `dp[2][4]` 的含义就是对于 `ac` 和 `babc` 这两个子字符串, 它们的最长公共子序列是 `2`, 当然我们求这个题的结果即是求 `dp[3][6]`. +对于下面这个例子, `dp[2][4]` 的含义就是对于 `ac` 和 `babc` 这两个子字符串, 它们的最长公共子序列是 `2`. ![1143-longest-common-subsequence](../../static/img/1143-longest-common-subsequence.png) @@ -77,8 +78,8 @@ keywords: ### 找状态转移方程 -对于这个问题, 状态转移就是在做选择, 即求 `s1` 和 `s2` 的最长公共子序列 `lcs`. 那么对于 `s1` 和 `s2` 中的每个字符, 要么在 `lcs` 中, 要么不在. -因此, 如果某个字符应该在 `lcs` 中, 那么这个字符肯定同时存在于 `s1` 和 `s2` 中; 否则, 至少有一个不在 `lcs` 中, 此时取最大的那个. 因此状态转移方程为: +对于这个问题, 状态转移就是在做选择, 即求 `s1` 和 `s2` 的最长公共子序列. 那么对于 `s1` 和 `s2` 中的每个字符, 要么在最长公共子序列中, 要么不在. +因此, 如果某个字符应该在最长公共子序列中, 那么这个字符肯定同时存在于 `s1` 和 `s2` 中; 否则, 至少有一个不在最长公共子序列中, 此时取最大的那个. 因此状态转移方程为: - 如果 `s[i - 1] === s[j - 1]`, 那么有 `dp[i][j] = dp[i - 1][j - 1] + 1` - 否则, `dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1])` diff --git a/leetcode-docs/medium/36-is-valid-sudoku.mdx b/leetcode-docs/medium/36-is-valid-sudoku.mdx index b5b802a8..f2f28548 100644 --- a/leetcode-docs/medium/36-is-valid-sudoku.mdx +++ b/leetcode-docs/medium/36-is-valid-sudoku.mdx @@ -18,7 +18,7 @@ keywords: - 数字 `1 - 9` 在每一列只能出现一次. - 数字 `1 - 9` 在每一个以粗实线分隔的 `3 * 3` 宫内只能出现一次. -注意: +注意: - 一个有效的数独(部分已被填充)不一定是可解的. - 只需要根据以上规则, 验证已经填入的数字是否有效即可. diff --git a/leetcode-docs/medium/516-longest-palindrome-subseq.mdx b/leetcode-docs/medium/516-longest-palindrome-subseq.mdx new file mode 100644 index 00000000..6f2d8596 --- /dev/null +++ b/leetcode-docs/medium/516-longest-palindrome-subseq.mdx @@ -0,0 +1,83 @@ +--- +id: 516-longest-palindrome-subseq +title: 最长回文子序列 +sidebar_label: 516. 最长回文子序列 +keywords: + - Dynamic Programming +--- + +:::success Tips +题目类型: Dynamic Programming + +相关题目: + +- [10. 正则表达式匹配](/leetcode/hard/10-is-match) +- [44. 通配符匹配](/leetcode/hard/44-is-match) +- [72. 编辑距离](/leetcode/hard/72-min-distance) +- [115. 不同的子序列](/leetcode/hard/115-num-distinct) +- [583. 两个字符串的删除操作](/leetcode/medium/583-min-distance) +- [1143. 最长公共子序列](/leetcode/medium/1143-longest-common-subsequence) + +::: + +## 题目 + +给你一个字符串 `s`, 找出其中最长的回文子序列, 并返回该序列的长度. + +子序列定义为: 不改变剩余字符顺序的情况下, 删除某些字符或者不删除任何字符形成的一个序列. + +:::note 提示: + +- `1 <= s.length <= 1000` +- `s` 仅由数字和英文字母组成 + +::: + +:::info 示例 + +```ts +输入: s = "bbbab" +输出: 4 +解释: 一个可能的最长回文子序列为 "bbbb" +``` + +```ts +输入: s = "cbbd" +输出: 2 +解释: 一个可能的最长回文子序列为 "bb" +``` + +::: + +## 题解 + +对于一个子序列而言, 如果它是回文子序列, 并且长度大于 2, 那么将它首尾的两个字符去除之后, 它仍然是个回文子序列. + +```ts +/** + * @param {string} s + * @return {number} + */ +var longestPalindromeSubseq = function (s) { + const n = s.length + const dp = new Array(n + 1).fill(0).map(() => new Array(n + 1).fill(0)) + + // 反着遍历保证正确的状态转移 + for (let i = n - 1; i >= 0; i--) { + // 如果只有一个字符, 一定是回文 + dp[i][i] = 1 + + const char1 = s[i] + for (let j = i + 1; j < n; j++) { + const char2 = s[j] + if (char1 === char2) { + dp[i][j] = dp[i + 1][j - 1] + 2 + } else { + dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]) + } + } + } + + return dp[0][n - 1] +} +``` diff --git a/leetcode-docs/medium/583-min-distance.mdx b/leetcode-docs/medium/583-min-distance.mdx index 73752566..ccae8461 100644 --- a/leetcode-docs/medium/583-min-distance.mdx +++ b/leetcode-docs/medium/583-min-distance.mdx @@ -15,6 +15,7 @@ keywords: - [44. 通配符匹配](/leetcode/hard/44-is-match) - [72. 编辑距离](/leetcode/hard/72-min-distance) - [115. 不同的子序列](/leetcode/hard/115-num-distinct) +- [516. 最长回文子序列](/leetcode/medium/516-longest-palindrome-subseq) - [1143. 最长公共子序列](/leetcode/medium/1143-longest-common-subsequence) ::: diff --git a/leetcode-docs/medium/80-remove-duplicates.mdx b/leetcode-docs/medium/80-remove-duplicates.mdx index 20a14374..503e20be 100644 --- a/leetcode-docs/medium/80-remove-duplicates.mdx +++ b/leetcode-docs/medium/80-remove-duplicates.mdx @@ -81,7 +81,7 @@ var removeDuplicates = function (nums) { -对于此类问题, 为了让解法更具有一般性,我们将原问题的**保留 `2` 位**修改为**保留 `k` 位**, 我们应该进行如下考虑: +对于此类问题, 为了让解法更具有一般性, 我们将原问题的**保留 `2` 位**修改为**保留 `k` 位**, 我们应该进行如下考虑: - 由于是保留 `k` 个相同数字, 对于前 `k` 个数字, 我们可以直接保留 - 对于后面的任意数字, 能够保留的前提是: 与当前写入的位置前面的第 `k` 个元素进行比较, 不相同则保留 diff --git a/leetcode-docs/medium/95-generate-trees.mdx b/leetcode-docs/medium/95-generate-trees.mdx index d707eb6d..2cfd5d86 100644 --- a/leetcode-docs/medium/95-generate-trees.mdx +++ b/leetcode-docs/medium/95-generate-trees.mdx @@ -81,5 +81,5 @@ var generateTrees = function (n) { ## 复杂度分析 -- 时间复杂度:卡特兰数 +- 时间复杂度: 卡特兰数 - 空间复杂度: 卡特兰数 diff --git a/leetcode-docs/medium/96-num-trees.mdx b/leetcode-docs/medium/96-num-trees.mdx index b58ed937..284d32dd 100644 --- a/leetcode-docs/medium/96-num-trees.mdx +++ b/leetcode-docs/medium/96-num-trees.mdx @@ -38,7 +38,7 @@ keywords: ## 题解 -给定一个有序序列 `1` 到 `n`,为了构建出一棵二叉搜索树, 我们可以遍历每个数字 `i`, 将该数字作为树根, 将 `1` 到 `i - 1` 序列作为左子树,将 `i + 1` 到 `n` 序列作为右子树. +给定一个有序序列 `1` 到 `n`,为了构建出一棵二叉搜索树, 我们可以遍历每个数字 `i`, 将该数字作为树根, 将 `1` 到 `i - 1` 序列作为左子树, 将 `i + 1` 到 `n` 序列作为右子树. 接着我们可以按照同样的方式递归构建左子树和右子树. ```ts diff --git a/leetcode-docs/medium/99-recover-tree.mdx b/leetcode-docs/medium/99-recover-tree.mdx index 4533e707..54a93def 100644 --- a/leetcode-docs/medium/99-recover-tree.mdx +++ b/leetcode-docs/medium/99-recover-tree.mdx @@ -26,17 +26,17 @@ keywords: ![33-search](../../static/img/99-recover-tree-1.jpg) ```ts -输入:root = [1,3,null,null,2] -输出:[3,1,null,null,2] -解释:3 不能是 1 的左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。 +输入: root = [1,3,null,null,2] +输出: [3,1,null,null,2] +解释: 3 不能是 1 的左孩子, 因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。 ``` ![33-search](../../static/img/99-recover-tree-2.jpg) ```ts -输入:root = [3,1,4,null,null,2] -输出:[2,1,4,null,null,3] -解释:2 不能在 3 的右子树中,因为 2 < 3 。交换 2 和 3 使二叉搜索树有效。 +输入: root = [3,1,4,null,null,2] +输出: [2,1,4,null,null,3] +解释: 2 不能在 3 的右子树中, 因为 2 < 3 。交换 2 和 3 使二叉搜索树有效。 ``` ::: @@ -44,7 +44,7 @@ keywords: ## 题解 1. 由于是 BST, 所以使用中序遍历, 把所有节点存储到 `list` 中 -2. 遍历这个列表 `list`, 由于 BST 的中序遍历应当是从小到大排列的, 所以如果前面的 val 大于了后面的 val, 说明后面这个应当靠前. +2. 遍历这个列表 `list`, 由于 BST 的中序遍历应当是从小到大排列的, 所以如果前面的 `val` 大于了后面的 `val`, 说明后面这个应当靠前. 3. 找到两个需要交换的, 交换他们的值即可 ```ts diff --git "a/src/leetcode/javascript/medium/516.\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\345\272\217\345\210\227.js" "b/src/leetcode/javascript/medium/516.\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\345\272\217\345\210\227.js" new file mode 100644 index 00000000..397572cd --- /dev/null +++ "b/src/leetcode/javascript/medium/516.\346\234\200\351\225\277\345\233\236\346\226\207\345\255\220\345\272\217\345\210\227.js" @@ -0,0 +1,31 @@ +/* + * @lc app=leetcode.cn id=516 lang=javascript + * + * [516] 最长回文子序列 + */ + +// @lc code=start +/** + * @param {string} s + * @return {number} + */ +var longestPalindromeSubseq = function (s) { + const n = s.length + const dp = new Array(n + 1).fill(0).map(() => new Array(n + 1).fill(0)) + + for (let i = n - 1; i >= 0; i--) { + dp[i][i] = 1 + const char1 = s[i] + for (let j = i + 1; j < n; j++) { + const char2 = s[j] + if (char1 === char2) { + dp[i][j] = dp[i + 1][j - 1] + 2 + } else { + dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]) + } + } + } + + return dp[0][n - 1] +} +// @lc code=end diff --git a/src/leetcode/rust/src/medium/mod.rs b/src/leetcode/rust/src/medium/mod.rs index 4b4e578e..7ca3f486 100644 --- a/src/leetcode/rust/src/medium/mod.rs +++ b/src/leetcode/rust/src/medium/mod.rs @@ -46,6 +46,7 @@ pub mod question_494; pub mod question_5; pub mod question_50; pub mod question_503; +pub mod question_516; pub mod question_518; pub mod question_528; pub mod question_53; diff --git a/src/leetcode/rust/src/medium/question_516.rs b/src/leetcode/rust/src/medium/question_516.rs new file mode 100644 index 00000000..1c483194 --- /dev/null +++ b/src/leetcode/rust/src/medium/question_516.rs @@ -0,0 +1 @@ +pub fn foo() -> () {} \ No newline at end of file