统计字符串中不同回文子序列的个数
2022/6/25 23:33:37
本文主要是介绍统计字符串中不同回文子序列的个数,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
统计字符串中不同回文子序列的个数
作者:Grey
原文地址: 统计字符串中不同回文子序列的个数
问题描述
给定一个字符串str,当然可以生成很多子序列,返回有多少个子序列是回文子序列,空序列不算回文,比如,str = “aba”
回文子序列有
{a}:0位置上的a {a}:2位置上的a {a,a} {b} {a,b,a}
所以返回5。
暴力解法
枚举每个子序列,然后判断子序列是否是回文,代码如下
public static int ways1(String str) { if (str == null || str.length() == 0) { return 0; } char[] s = str.toCharArray(); char[] path = new char[s.length]; return process(str.toCharArray(), 0, path, 0); } // 枚举每个位置要或者不要情况下,得到回文子序列的个数是多少 public static int process(char[] s, int si, char[] path, int pi) { if (si == s.length) { return isP(path, pi) ? 1 : 0; } int ans = process(s, si + 1, path, pi); path[pi] = s[si]; ans += process(s, si + 1, path, pi + 1); return ans; } // 判断path串中0...pi-1是不是回文 public static boolean isP(char[] path, int pi) { if (pi == 0) { return false; } int L = 0; int R = pi - 1; while (L < R) { if (path[L++] != path[R--]) { return false; } } return true; }
动态规划解
定义二维数组dp
,数组长度假设为n
int[][] dp = new int[n][n]
dp[i][j]
的含义是:字符串[i...j]
区间内可以得到的最多回文子序列个数,所以,dp[0][n-1]
的值就是我们需要求的最终答案。
根据dp
数组的含义,我们可以得到,二维矩阵dp
中的对角线上的值都是1, 对角线上面的位置也可以很容易得出,见如下注释
// 对角线上的值都是1 for (int i = 0; i < n; i++) { dp[i][i] = 1; } // 对角线上面的位置,即dp[i][i+1]上的值 // 如果str[i] == str[i+1],比如:aa,有三个回文子序列,分别是{a},{a},{aa} // 如果str[i] != str[i+1],比如:ab,有两个回文子序列,分别是 {a},{b} for (int i = 0; i < n - 1; i++) { dp[i][i+1] = str[i] == str[i+1] ? 3 : 2; }
接下来考虑普遍位置dp[i][j]
,可以有如下几种情况:
情况一,i
位置的字符弃而不用,那么dp[i][j] = dp[i+1][j]
;
情况二,j
位置的字符弃而不用,那么dp[i][j] = dp[i][j-1]
;
基于情况一和情况二,
dp[i][j] = dp[i+1][j] + dp[i][j-1]
这个时候,其实是算重了一部分,算重的部分是dp[i+1][j-1]
,所以
dp[i][j] = dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1]
如果str[i] == str[j]
,则存在情况三,情况三中,str[i]
和str[j]
可都保留,与区间[i+1...j-1]
形成回文串,str[i]
也可以单独和str[j]
形成一个回文串。所以,情况三
// dp[i][j]分成两部分 // 其中: // 第一部分:dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1] 表示i位置和j位置弃而不用的情况下,得到的答案数 // 第二部分:dp[i + 1][j - 1] + 1 表示在情况三下,同时使用str[i]和str[j]位置得到的答案数 dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1] + dp[i + 1][j - 1] + 1
动态规划解法的完整代码
public static int ways2(String s) { if (s == null || s.length() == 0) { return 0; } char[] str = s.toCharArray(); int n = str.length; int[][] dp = new int[n][n]; // 对角线都是1 for (int i = 0; i < n; i++) { dp[i][i] = 1; } for (int i = 0; i < n - 1; i++) { dp[i][i + 1] = str[i] == str[i + 1] ? 3 : 2; } for (int i = n - 3; i >= 0; i--) { for (int j = i + 2; j < n; j++) { // 减去dp[i+1][j-1]是因为算重复了 dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1]; if (str[i] == str[j]) { // dp[i][j]分成两部分 // 其中: // 第一部分:dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1] 表示i位置和j位置弃而不用的情况下,得到的答案数 // 第二部分:dp[i + 1][j - 1] + 1 表示在情况三下,同时使用str[i]和str[j]位置得到的答案数 dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1] + dp[i + 1][j - 1] + 1; } } } return dp[0][n - 1]; }
类似问题
LeetCode 730. 统计不同回文子序列
更多
算法和数据结构笔记
这篇关于统计字符串中不同回文子序列的个数的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-26Java语音识别项目资料:新手入门教程
- 2024-11-26JAVA语音识别项目资料:新手入门教程
- 2024-11-26Java语音识别项目资料:入门与实践指南
- 2024-11-26Java云原生资料入门教程
- 2024-11-26Java云原生资料入门教程
- 2024-11-26Java云原生资料:新手入门教程
- 2024-11-25Java创意资料:新手入门的创意学习指南
- 2024-11-25JAVA对接阿里云智能语音服务资料详解:新手入门指南
- 2024-11-25Java对接阿里云智能语音服务资料详解
- 2024-11-25Java对接阿里云智能语音服务资料详解