作者: 负雪明烛
id: fuxuemingzhu
个人博客: http://fuxuemingzhu.cn/


题目地址:https://leetcode.com/problems/longest-palindromic-subsequence/description/

题目描述

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

Example 1:

Input:

"bbbab"
Output:
4
One possible longest palindromic subsequence is "bbbb".

Example 2:

Input:

"cbbd"
Output:
2
One possible longest palindromic subsequence is "bb".

题目大意

找出一个字符串中最长的回文序列的长度。注意序列可以是不连续的,而子字符串是连续的。

解题思路

做完昨天的每日一题 446. 等差数列划分 II - 子序列 之后,相信大家对于子序列问题的套路已经更加了解了。子序列问题不能用滑动窗口了,可以用动态规划来解决。子序列问题的经典题目就是 300. 最长递增子序列,务必掌握。

先从整体思路说起。

子序列问题,由于是数组中的非连续的一个序列,使用动态规划求解时,避免不了二重循环:第一重循环是求解动态规划的每一个状态

d

p

[

i

]

,

(

0

<

=

i

<

=

N

)

dp[i], (0 <= i <= N)

dp[i],(0<=i<=N) ,第二重循环是向前寻找上一个子序列的结尾

j

,

(

0

<

=

j

<

i

)

j ,(0 <= j < i)

j,(0<=j<i)$ 来和

i

i

i 一起构成满足题意的新的子序列。

  • 对于「最长递增子序列」问题,我们对

    i

    ,

    j

    i, j

    i,j 的要求是

    n

    u

    m

    s

    [

    i

    ]

    >

    n

    u

    m

    s

    [

    j

    ]

    nums[i] > nums[j]

    nums[i]>nums[j],即递增;

  • 对于「能构成等差数列的子序列」问题,我们对

    i

    ,

    j

    i, j

    i,j 的要求是

    n

    u

    m

    [

    i

    ]

    num[i]

    num[i] 可以在

    n

    u

    m

    s

    [

    j

    ]

    nums[j]

    nums[j] 的基础上构成等差数列。

  • 对于「最长回文子序列」问题,我们对

    i

    ,

    j

    i, j

    i,j 本身的取值没有要求,但是希望能够成最长的回文子串。

在动态规划问题中,我们找到一个符合条件的

j

j

j ,然后就可以通过状态转移方程由

d

p

[

j

]

dp[j]

dp[j] 推导出

d

p

[

i

]

dp[i]

dp[i] 。

然后,我理一下本题的解法。

当已知一个序列是回文时,在其首尾添加元素后的序列存在两种情况:

  1. 首尾元素相等,则最长回文的长度 + 2;
  2. 首尾元素不相等,则最长回文序列长度为 仅添加首元素时的最长回文长度 与 仅添加尾元素时的最长回文长度 的最大值。

状态定义

d

p

[

i

]

[

j

]

dp[i][j]

dp[i][j] 表示

s

[

i

j

]

s[i…j]

s[i…j] 中的最长回文序列长度。

状态转移方程

  1. i

    >

    j

    i > j

    i>j,

    d

    p

    [

    i

    ]

    [

    j

    ]

    =

    0

    dp[i][j] = 0

    dp[i][j]=0;

  2. i

    =

    =

    j

    i == j

    i==j,

    d

    p

    [

    i

    ]

    [

    j

    ]

    =

    1

    dp[i][j] = 1

    dp[i][j]=1;

  3. i

    <

    j

    i < j

    i<j 且

    s

    [

    i

    ]

    =

    =

    s

    [

    j

    ]

    s[i] == s[j]

    s[i]==s[j],

    d

    p

    [

    i

    ]

    [

    j

    ]

    =

    d

    p

    [

    i

    +

    1

    ]

    [

    j

    1

    ]

    +

    2

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

    dp[i][j]=dp[i+1][j−1]+2;

  4. i

    <

    j

    i < j

    i<j 且

    s

    [

    i

    ]

    =

    s

    [

    j

    ]

    s[i]!= s[j]

    s[i]!=s[j],

    d

    p

    [

    i

    ]

    [

    j

    ]

    =

    m

    a

    x

    (

    d

    p

    [

    i

    +

    1

    ]

    [

    j

    ]

    d

    p

    [

    i

    ]

    [

    j

    1

    ]

    )

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

    dp[i][j]=max(dp[i+1][j],dp[i][j−1]);

遍历顺序
从状态转移方程可以看出,计算

d

p

[

i

]

[

j

]

dp[i][j]

dp[i][j] 时需要用到

d

p

[

i

+

1

]

[

j

1

]

dp[i+1][j - 1]

dp[i+1][j−1] 和

d

p

[

i

+

1

]

[

j

]

dp[i + 1][j]

dp[i+1][j],所以对于

i

i

i 的遍历应该从后向前;对于

j

j

j 的遍历应该从前向后。

返回结果
最后返回

d

p

[

0

]

[

s

.

l

e

n

g

t

h

(

)

1

]

dp[0][s.length() - 1]

dp[0][s.length()−1]。

代码

提供了三种语言的代码。

java 代码

class Solution {
public int longestPalindromeSubseq(String s) {
int size = s.length();
int[][] dp = new int[size][size];
for(int i = size - 1; i >= 0; i--){
dp[i][i] = 1;
for(int j = i + 1; j < size; j++){
if(s.charAt(i) == s.charAt(j)){
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][size - 1];
}
}

C++代码:

class Solution {
public:
int longestPalindromeSubseq(string s) {
int size = s.size();
vector<vector<int>> dp(size, vector<int>(size, 0));
for(int i = size - 1; i >= 0; i--){
dp[i][i] = 1;
for(int j = i + 1; j < size; j++){
if(s[i] == s[j]){
dp[i][j] = dp[i + 1][j - 1] + 2;
}else{
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
}
}
}
return dp[0][size - 1];
}
};

python 代码:

class Solution:
def longestPalindromeSubseq(self, s):
n = len(s)
dp = [[0] * n for _ in range(n)]
for i in range(n - 1, -1, -1):
dp[i][i] = 1
for j in range(i + 1, n):
if s[i] == s[j]:
dp[i][j] = dp[i + 1][j - 1] + 2
else:
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])
return dp[0][n - 1]
  • 时间复杂度:

    O

    (

    N

    2

    )

    O(N^2)

    O(N2)

  • 空间复杂度:

    O

    (

    N

    2

    )

    O(N^2)

    O(N2)

刷题心得

子序列的动态规划解法:两重循环。其实就看对于每个

i

i

i,当找到满足题目要求的

j

j

j 的时候,状态转移方程怎么变化。

参考:http://blog.csdn.net/camellhf/article/details/70337501

日期

2018 年 3 月 15 日 --雾霾消散,春光明媚
2021 年 8 月 12 日——对面在装修,很吵

【LeetCode】516. Longest Palindromic Subsequence 最长回文子序列的更多相关文章

  1. [LeetCode] 516. Longest Palindromic Subsequence 最长回文子序列

    Given a string s, find the longest palindromic subsequence's length in s. You may assume that the ma ...

  2. 516 Longest Palindromic Subsequence 最长回文子序列

    给定一个字符串s,找到其中最长的回文子序列.可以假设s的最大长度为1000. 详见:https://leetcode.com/problems/longest-palindromic-subseque ...

  3. [LeetCode] Longest Palindromic Subsequence 最长回文子序列

    Given a string s, find the longest palindromic subsequence's length in s. You may assume that the ma ...

  4. Leetcode 5. Longest Palindromic Substring(最长回文子串, Manacher算法)

    Leetcode 5. Longest Palindromic Substring(最长回文子串, Manacher算法) Given a string s, find the longest pal ...

  5. [LeetCode] 5. Longest Palindromic Substring 最长回文子串

    Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...

  6. [leetcode]5. Longest Palindromic Substring最长回文子串

    Given a string s, find the longest palindromic substring in s. You may assume that the maximum lengt ...

  7. LN : leetcode 516 Longest Palindromic Subsequence

    lc 516 Longest Palindromic Subsequence 516 Longest Palindromic Subsequence Given a string s, find th ...

  8. 516. Longest Palindromic Subsequence最长的不连续回文串的长度

    [抄题]: Given a string s, find the longest palindromic subsequence's length in s. You may assume that ...

  9. [leetcode]516. Longest Palindromic Subsequence最大回文子序列

    Given a string s, find the longest palindromic subsequence's length in s. You may assume that the ma ...

随机推荐

  1. Django向数据库批量插入数据

    # 如何向数据库一次性插入多条数据 # 方法一:效率极低,不推荐使用 for i in range(1000): models.Book.objects.create(title=f'第{i}本书') ...

  2. typedef 的用法

    [2]typedef (1)在C语言中,允许使用关键字typedef定义新的数据类型 其语法如下: typedef <已有数据类型> <新数据类型>; 如: typedef i ...

  3. xmake v2.6.1 发布,使用 Lua5.4 运行时,Rust 和 C++ 混合编译支持

    xmake 是一个基于 Lua 的轻量级跨平台构建工具,使用 xmake.lua 维护项目构建,相比 makefile/CMakeLists.txt,配置语法更加简洁直观,对新手非常友好,短时间内就能 ...

  4. linux下定位异常消耗的线程实战分析

    前言: 之前分享过一篇Linux开发coredump文件分析实战分享 ,今天再来分享一篇实战文章. 在我们嵌入式linux开发过程中,开发过程中我们经常会使用多进程.多线程开发.那么多线程使用过程中, ...

  5. MapReduce03 框架原理InputFormat数据输入

    目录 1 InputFormat数据输入 1.1 切片与MapTask并行度决定机制 问题引出 MapTask并行度决定机制 Job提交流程源码 切片源码 1.2 FileInputFormat切片机 ...

  6. FileReader (三) - 网页拖拽并预显示图片简单实现

    以下是一个很贱很简单的一个 在网页上图拽图片并预显示的demo. 我是从https://developer.mozilla.org/en-US/docs/Web/API/FileReader#Stat ...

  7. 【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(四)-介绍库函数,获取一些SD卡的信息

    其他链接 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(一)-初步认识SD卡 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(二)-了解SD总线,命令的相关介绍 ...

  8. SpringCloud微服务服务间调用之OpenFeign介绍

    开发微服务,免不了需要服务间调用.Spring Cloud框架提供了RestTemplate和FeignClient两个方式完成服务间调用,本文简要介绍如何使用OpenFeign完成服务间调用. Op ...

  9. java代码从出生到执行的过程浅析

    阅读<深入理解java虚拟机 第二版 JVM高级特性与最佳实践> - jdk版本为1.6 1.什么是编译型语言.解释型语言 解释型语言:源代码不是直接翻译成机器语言,而是先翻译成中间代码, ...

  10. linux系统目录初识

    目录 今日内容概要 内容详细 系统目录结构介绍 目录结构知识描述 今日内容概要 系统目录结构介绍 目录结构详细描述 内容详细 系统目录结构介绍 # 1.linux系统中的目录 一切从根开始 结构拥有层 ...