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

动态规划算法专题(六):回文串问题

目录

1、回文子串("引子题")

1.1 算法原理 

1.2 算法代码

2、最长回文子串

2.1 算法原理

2.2 算法代码

3、分割回文串 IV(hard)

3.1 算法原理

3.2 算法代码

4、分割字符串 II(hard)

4.1 算法原理 

4.2 算法代码

5、最长回文子序列

5.1 算法原理 

5.2 算法代码

6、让字符串成为回文串的最少插入次数(hard)

6.1 算法原理

6.2 算法代码


1、回文子串("引子题")

. - 力扣(LeetCode)

1.1 算法原理 

  • 状态表示:

dp[i][j]:[i, j]区间内的子串,是否回文(i <= j)

  • 状态转移方程:

s[i] == s[j]:

1. i == j --> true 
2. i+1==j --> s(i) == s(j) ? true : false
3. s(i) == s(j) --> dp[i+1][j-1]

  • 初始化:

无需初始化(状态转移方程的前两种情况已处理特殊的边界情况)

  • 建表顺序:

从下往上(根据状态转移方程)

  • 返回值:

dp表中有几个true

1.2 算法代码

class Solution {public int countSubstrings(String ss) {char[] s = ss.toCharArray();int n = s.length;boolean[][] dp = new boolean[n][n];int ret = 0;// 填表 --> 从下往上for(int i = n - 1; i >= 0; i--) {// j >= ifor(int j = i; j < n; j++) {if(s[i] == s[j]) {if(i == j) dp[i][j] = true;else if(i + 1 == j) dp[i][j] = true;else dp[i][j] = dp[i + 1][j - 1];}if(dp[i][j]) ret++;}}return ret;}
}

2、最长回文子串

. - 力扣(LeetCode)

2.1 算法原理

本题算法原理与题一完全一致,最终返回最长的回文子串即可。

  • 状态表示:

dp[i][j]:[i, j]区间内的子串,是否回文(i <= j)

  • 状态转移方程:

s[i] == s[j]:

1. i == j --> true 
2. i+1==j --> s(i) == s(j) ? true : false
3. s(i) == s(j) --> dp[i+1][j-1]

  • 初始化:

无需初始化(状态转移方程的前两种情况已处理特殊的边界情况)

  • 建表顺序:

从下往上(根据状态转移方程)

  • 返回值:

最长回文子串

2.2 算法代码

class Solution {public String longestPalindrome(String ss) {char[] s = ss.toCharArray();int n = s.length;boolean[][] dp = new boolean[n][n];String ret = "";int begin = 0;int end = 0;// 建表 --> 从下往上for(int i = n - 1; i >= 0; i--) {for(int j = i; j < n; j++) {// i <= jif(s[i] == s[j]) {if(i == j) dp[i][j] = true;else if(i + 1 == j) dp[i][j] = true;else dp[i][j] = dp[i + 1][j - 1];}if(dp[i][j]) {// 记录最长回文子串的起始和末尾位置if(j - i + 1 > end - begin + 1) {begin = i;end = j;}} }}return ss.substring(begin, end + 1);}
}

3、分割回文串 IV(hard)

. - 力扣(LeetCode)

3.1 算法原理

本题算法原理依旧是在题一判断好哪些子串是回文的基础上,分割字符串,判断是否存在三个回文串即可。

  • 状态表示:

dp[i][j]:[i, j]区间内的子串,是否回文(i <= j)

  • 状态转移方程:

s[i] == s[j]:

1. i == j --> true 
2. i+1==j --> s(i) == s(j) ? true : false
3. s(i) == s(j) --> dp[i+1][j-1]

  • 初始化:

无需初始化(状态转移方程的前两种情况已处理特殊的边界情况)

  • 建表顺序:

从下往上(根据状态转移方程)

  • 返回值:

是否存在三个回文串。

3.2 算法代码

class Solution {public boolean checkPartitioning(String ss) {char[] s = ss.toCharArray();int n = s.length;boolean[][] dp = new boolean[n][n];for(int i = n - 1; i >= 0; i--) {for(int j = i; j < n; j++) {if(s[i] == s[j]) {if(i == j) dp[i][j] = true;else if(i + 1 == j) dp[i][j] = true;else dp[i][j] = dp[i + 1][j - 1];}}}// 从 i,j 位置 分割字符串for(int i = 1; i < n; i++) {for(int j = i; j < n - 1; j++) {if(dp[0][i - 1] && dp[i][j] && dp[j + 1][n - 1]) return true;}}return false;}
}

4、分割字符串 II(hard)

. - 力扣(LeetCode)

4.1 算法原理 

本题仍然在题一中 通过二维dp保存所有子串的是否回文的信息 的基础上解题。

  • 状态表示:

dp[i]:以[0, i]区间内的子串,最少的分割次数

  • 状态转移方程:

1. 0~i 回文 --> 0
2. 0~i 不回文 --> 0 < j < = i --> 若子串[ j, i ]回文 --> min(dp[ j - 1 ] + 1)

  • 初始化:

dp表中所有元素初始化为Integer.MAX_VALUE

  • 建表顺序:

从左往右

  • 返回值:

dp[n-1]

4.2 算法代码

class Solution {public int minCut(String ss) {char[] s = ss.toCharArray();int n = s.length;boolean[][] isPal = new boolean[n][n];for (int i = n - 1; i >= 0; i--) {for (int j = i; j < n; j++) {if (s[i] == s[j]) {if (i == j)isPal[i][j] = true;else if (i + 1 == j)isPal[i][j] = true;elseisPal[i][j] = isPal[i + 1][j - 1];}}}int[] dp = new int[n];// 初始化Arrays.fill(dp, Integer.MAX_VALUE);for (int i = 0; i < n; i++) {if (isPal[0][i])dp[i] = 0;else {// j --> (0, i]for (int j = 1; j <= i; j++) {if (isPal[j][i])dp[i] = Math.min(dp[i], dp[j - 1] + 1);}}}return dp[n - 1];}
}

5、最长回文子序列

. - 力扣(LeetCode)

5.1 算法原理 

  • 状态表示:

dp[i][j]:s字符串[i , j]区间内的所有子序列中,最长回文子序列的长度

  • 状态转移方程:

1. s[i] == s[j]:

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

2. s[i] != s[j]:

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

  • 初始化:

无需初始化

  • 建表顺序:

从下往上填写每一行,每一行从左往右填写每一列

  • 返回值:

dp[0][n-1]

5.2 算法代码

class Solution {public int longestPalindromeSubseq(String ss) {char[] s = ss.toCharArray();int n = s.length;int[][] dp = new int[n][n];// 从下往上填每一行// 每一行从左往右填每一列for(int i = n - 1; i >= 0; i--) {for(int j = i; j < n; j++) {if(s[i] == s[j]) {if(i == j) dp[i][j] = 1;else if(i + 1 == j) dp[i][j] = 2;else 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];}
}

6、让字符串成为回文串的最少插入次数(hard)

. - 力扣(LeetCode)

6.1 算法原理

  • 状态表示:

dp[i][j]:字符串[i, j]区间内的子串,使它成为回文串的最小插入次数

  • 状态转移方程:

s[i] == s[j]:

1. i == j --> 0

2. i + 1 == j --> 0

3. dp[i + 1][j - 1]

s[i] != s[j]:

min(dp[i + 1][j], dp[i][j - 1]) + 1;

  • 初始化:

无需初始化

  • 建表顺序:

从上到下每一行
从左往右每一列

  • 返回值:

dp[0][n-1]

6.2 算法代码

class Solution {public int minInsertions(String ss) {char[] s = ss.toCharArray();int n = s.length;int[][] dp = new int[n][n];// 无需初始化// 建表 --> 从上往下每一行,从左往右每一列for(int i = n - 1; i >= 0; i--) {for(int j = i; j < n; j++) {if(s[i] == s[j]) {if(i == j) dp[i][j] = 0;else if(i + 1 == j) dp[i][j] = 0;else 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[0][n - 1];}
}

END


http://www.mrgr.cn/news/46778.html

相关文章:

  • docker 部署 MantisBT
  • GPT Notes 3.2.1.2 | 最强GPT解锁会员版无需登录无限制使用
  • RabbitMQ的工作模式
  • 汇总统计数据--SQL中聚集函数的使用
  • 第五章:计算机网络
  • MySQL主从:如何处理“Got Fatal Error 1236”或 MY-013114 错误(percona译文)
  • k8s中pod的管理
  • Python案例--copy复制
  • 手写一个内存池-页内分配
  • 【CSS3】css开篇基础(2)
  • umap结果不能复现
  • linux基础-------堡垒机与跳板机
  • 【LeetCode】修炼之路-0004-Median of Two Sorted Arrays【python】
  • keil5| printf()函数 | 使用技巧 | STM32|UARST串口输出
  • 逼近理论及应用精解【11】
  • JS中的异步和Promise
  • 算法.图论-bfs及其拓展
  • k8s、prometheus、grafana数据采集和展示的链路流程
  • 「字符串」Z函数(扩展KMP|exKMP)/ LeetCode 2223(C++)
  • 基于SpringBoot问卷调查系统小程序【附源码】
  • Linux系统中,文件和文件夹的权限和所有权核心概念
  • 汇编语言_王爽_寄存器
  • Kubernetes 探秘:深入理解 StatefulSet 的拓扑状态
  • house_of_muney
  • 如何在两台服务器之间迁移 MySQL 数据库
  • 肺腺癌预后新指标:全切片图像中三级淋巴结构密度的自动化量化|文献精析·24-10-09