Fancy DSA Fancy DSA
数据结构
算法
LeetCode
  • 关于
  • 导航 (opens new window)
  • 分类
  • 标签
  • 归档
设计模式 (opens new window)
博客 (opens new window)
GitHub (opens new window)

Jonsam NG

想的更多,也要想的更远
数据结构
算法
LeetCode
  • 关于
  • 导航 (opens new window)
  • 分类
  • 标签
  • 归档
设计模式 (opens new window)
博客 (opens new window)
GitHub (opens new window)
  • 开始上手
  • Plan 计划
  • Roadmap 路线
  • 算法简介
  • Sort 排序

  • Search 搜索

  • Recursive 递归

  • Graph 图

  • Tree 树

  • Math 数学

  • Hash 哈希

  • String 字符串

  • BitManipulation 位操纵

  • Backtracking 回溯

  • DynamicProgramming 动态规划

    • ClimbingStairs [爬楼梯]
    • CoinChange [钱币兑换]
    • EditDistance [编辑距离]
    • FibonacciNumber [斐波那契数]
    • FindMonthCalendar [月历]
    • KadaneAlgo [最大连续子数组和之Kadane算法]
    • LevenshteinDistance [莱文斯坦距离]
    • LongestCommonSubsequence [最长公共子序列]
    • LongestIncreasingSubsequence [最长递增子序列]
    • LongestPalindromicSubsequence [最长回文子序列]
      • 介绍
      • 实现
      • 参考
    • LongestValidParentheses [最长合法括号]
    • MaxNonAdjacentSum [最大非连接子集和]
    • MaxProductOfThree [最大三数积]
    • MinimumCostPath [最小代价路径]
    • NumberOfSubsetEqualToGivenSum [等和子集]
    • RodCutting [棒材切割问题]
    • Shuf [随机样本]
    • SieveOfEratosthenes [埃拉托斯特尼筛法]
    • SlidingWindow [滑窗]
    • SudokuSolver [数独]
    • TrappingRainWater [接住雨水]
    • TribonacciNumber [翠波那契数]
    • ZeroOneKnapsack [零一背包]
  • Cache 缓存

  • Array 数组

  • Ciphers 密码学

  • Conversions 转换

  • ProjectEuler 欧拉计划

  • 其他

  • 算法
  • DynamicProgramming 动态规划
jonsam
2022-09-26
目录

LongestPalindromicSubsequence [最长回文子序列]

# 介绍

给定一个字符串 s,找出 s 中最长的回文子序列的长度。你可以假设 s 的最大长度为 1000。

下面是一个处理了所有情况的递归解决方案:

// Every single character is a palindrome of length 1
L(i, i) = 1 for all indexes i in given sequence

// IF first and last characters are not same
If (X[i] != X[j])  L(i, j) =  max{L(i + 1, j),L(i, j - 1)} 

// If there are only 2 characters and both are same
Else if (j == i + 1) L(i, j) = 2  

// If there are more than two characters, and first and last 
// characters are same
Else L(i, j) =  L(i + 1, j - 1) + 2 
1
2
3
4
5
6
7
8
9
10
11
12

重叠子问题:下面是 LPS 问题的一个简单的递归实现。该实现简单地遵循了上述的递归结构。

// A utility function to get max of two integers 
function max(x, y) {
  return (x > y) ? x : y;
}
 
// Returns the length of the longest palindromic subsequence in seq    
function lps(seq, i, j)
{
  // Base Case 1: If there is only 1 character
  if (i == j) return 1;
  // Base Case 2: If there are only 2 characters and both are same 
  if (seq[i] == seq[j] && i + 1 == j) return 2;
  // If the first and last characters match 
  if (seq[i] == seq[j]) return lps(seq, i + 1, j - 1) + 2;
  // If the first and last characters do not match 
  return max(lps(seq, i, j - 1), lps(seq, i + 1, j));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 实现

# JavaScript

// A utility function to get max of two integers
function max(x,y) {
  return (x > y)? x : y;
}
 
// Returns the length of the longest palindromic subsequence in seq
function lps(seq)
{
  let n = seq.length;
  let i, j, cl;
  // Create a table to store results of subproblems
  let L = new Array(n);
  for(let x=0;x<n;x++) {
      L[x] = new Array(n);
      for(let y = 0; y < n; y++) L[x][y] = 0;
  }
    
  // Strings of length 1 are palindrome of length 1
  for (i = 0; i < n; i++) L[i][i] = 1;
            
  // Build the table. Note that the lower diagonal values of table are useless and not filled in the process.
  // The values are filled in a manner similar to Matrix Chain Multiplication DP solution (See https://www.geeksforgeeks.org/matrix-chain-multiplication-dp-8/).
  // cl is length of substring
  for (cl = 2; cl <= n; cl++) {
    for (i = 0; i < n -cl + 1; i++) {
        j = i + cl - 1;
        if (seq[i] == seq[j] && cl == 2) L[i][j] = 2;
        else if (seq[i] == seq[j]) L[i][j] = L[i + 1][j - 1] + 2;
        else L[i][j] = max(L[i][j - 1], L[i + 1][j]);
    }
  }
            
  return L[0][n - 1];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

或者:

/*
  LeetCode -> https://leetcode.com/problems/longest-palindromic-subsequence/

  Given a string s, find the longest palindromic subsequence's length in s.
  You may assume that the maximum length of s is 1000.

*/

const longestPalindromeSubsequence = function (s) {
  const n = s.length

  const dp = new Array(n).fill(0).map(item => new Array(n).fill(0).map(item => 0))

  // fill predefined for single character
  for (let i = 0; i < n; i++) dp[i][i] = 1;

  for (let i = 1; i < n; i++) {
    for (let j = 0; j < n - i; j++) {
      const col = j + i
      if (s[j] === s[col]) dp[j][col] = 2 + dp[j + 1][col - 1]
      else dp[j][col] = Math.max(dp[j][col - 1], dp[j + 1][col])
    }
  }

  return dp[0][n - 1]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

时间复杂度:O (n^2),比 Naive Recursive 实现的最坏情况下的时间复杂度好得多。

辅助空间:O (n^2), 创建一个表

使用动态规划的缓存技术:想法是反转给定的输入字符串并检查最长的公共子序列的长度。这将是最长的公共子序列的答案。

// A Dynamic Programming based JavaScript program for LPS problem
// Returns the length of the longest palindromic subsequence in seq
let dp;
 
// Returns the length of the longest palindromic subsequence in seq
function lps(s1, s2, n1, n2) {
  if (n1 == 0 || n2 == 0) return 0;
  if (dp[n1][n2] != -1) return dp[n1][n2];
  if (s1[n1 - 1] == s2[n2 - 1]) return dp[n1][n2] = 1 + lps(s1, s2, n1 - 1, n2 - 1);
  return dp[n1][n2] = Math.max(lps(s1, s2, n1 - 1, n2), lps(s1, s2, n1, n2 - 1));
}

// * Driver program to test above functions */
 
let seq = "GEEKSFORGEEKS";
let n = seq.length;
dp = new Array(1001);
for(let i=0;i<1001;i++) dp[i] = new Array(1001).fill(-1);
let s2 = seq.split('').reverse().join('');
lps(s2, seq, n, n)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 参考

  • Longest Palindromic Subsequence | DP-12 - GeeksforGeeks (opens new window)
编辑 (opens new window)
上次更新: 2022/11/01, 18:11:55
LongestIncreasingSubsequence [最长递增子序列]
LongestValidParentheses [最长合法括号]

← LongestIncreasingSubsequence [最长递增子序列] LongestValidParentheses [最长合法括号]→

最近更新
01
0-20题解
10-31
02
本章导读
10-31
03
算法与转换:Part1
10-28
更多文章>
Theme by Vdoing | Copyright © 2022-2022 Fancy DSA | Made by Jonsam by ❤
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式