赞
踩
给你一个字符串 s
,请你统计并返回这个字符串中 回文子串 的数目。
回文字符串 是正着读和倒过来读一样的字符串。
子字符串 是字符串中的由连续字符组成的一个序列。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 1:
输入:s = "abc" 输出:3 解释:三个回文子串: "a", "b", "c"
示例 2:
输入:s = "aaa" 输出:6 解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"
提示:
1 <= s.length <= 1000
s
由小写英文字母组成创建一个布尔类型的二维dp数组,dp[i][j]表示下标i到j的字符串是否是回文字符串。
如果s[i] != s[j],那么从下标i到j的字符串不是回文字符串,即dp[i][j] = false。
如果s[i] == s[j],那么dp[i][j]可以从三个方向推出来:
1、i == j 时,就一个字符,是回文串。
2、j - i = 1时,就是两个相同字符,例如aa,也是回文串。
3、j - i > 1时,就要判断从下标i+1到下标j-1的字符串是否是回文串了(也就是判断ij两端字符内部的字符串是否是回文串),即dp[i][j]=dp[i+1][j-1]。
dp数组每个元素都需先初始化成false。
根据递推公式,公式里dp[i][j]可能会由dp[i+1][j-1]推出来,也就是说处理上面之前就需先处理下面,处理左边右边之前先需处理左边,所以i是倒叙遍历,j是正序遍历,而根据dp的定义j是大于等于i的,所以遍历j的时候从j=i开始遍历。
代码如下:
- class Solution {
- public int countSubstrings(String s) {
- int len = s.length();
- boolean[][] dp = new boolean[len][len];//字符串i到j是否是回文串
- int sum = 0;
- for(int i = len - 1; i >= 0; i--) {
- char a = s.charAt(i);
- for(int j = i; j < len; j++) {
- if(s.charAt(j) == a) {//当字符ij相等时
- if(j - i <= 1 || dp[i + 1][j - 1]) {//字符串长度再两个字符以内的情况或者内部字符串是回文的情况下,这个字符串都是回文字符串
- dp[i][j] = true;
- sum++;
- }
- }
- }
- }
- // for(int i = 0; i < len; i++) {
- // for(int j = 0; j < len; j++) {
- // System.out.print(dp[i][j] + " ");
- // }
- // System.out.println();
- // }
- return sum;
- }
- }
给你一个字符串 s
,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
示例 1:
输入:s = "bbbab" 输出:4 解释:一个可能的最长回文子序列为 "bbbb" 。
示例 2:
输入:s = "cbbd" 输出:2 解释:一个可能的最长回文子序列为 "bb" 。
提示:
1 <= s.length <= 1000
s
仅由小写英文字母组成dp[i][j]表示从下表i到j的子串中最长回文子串的长度。
如果s[i]==s[j],那么有三种情况:
1、若j-i == 0,即子串只有一个字符,那么最长回文子串的长度为1,dp[i][j]=1;
2、若j-i ==1,即子串只有相等的两个字符,那么最长回文子串的长度为2,dp[i][j]=2;
3、若j-i > 1,那么dp[i][j] = dp[i+1][j-1]+2,即i到j的最长回文子串长度等于其内部(不包含两端)最长回文子串的长度加2。
如果s[i] != s[j] ,那么dp[i][j]可以有两个方向推导出来:
1、删掉左端的i字符串,那么i到j的最长回文子串长度就是i+1到j的最长回文子串长度,即dp[i][j]=dp[i+1][j];
2、删掉右端的j字符,那么i到j的最长回文子串长度就是i到j-1的最长回文子串长度,即dp[i][j]=dp[i][j-1];
dp数组所有元素初始化为0。
根据递推公式中,dp[i][j]可能会有dp[i+1][j-1]推出来,所以需要先处理大的i和小的j,也即倒叙遍历i,正序遍历j,而根据dp数组的定义i是字符串的左区间,j是右区间,所以j需要大于等于0,也即j从j=i开始向后遍历。
代码如下:
- class Solution {
- public int longestPalindromeSubseq(String s) {
- int len = s.length();
- int[][] dp = new int[len][len];//dp[i][j]表示从下表i到j的字符串中最长回文串的长度
- for(int i = len - 1; i >= 0; i--) {
- char a = s.charAt(i);
- for(int j = i; j < len; j++) {
- if(s.charAt(j) == a) {//如果ij相等,分三种情况
- if(j - i == 0) dp[i][j] = 1;//i到j的字符串长度为1,那么只有一个字符,最长回文串长度为1
- else if(j - i == 1) dp[i][j] = 2;//i到j的字符串长度为2,只有两个相等的字符,最长回文长度为2
- else dp[i][j] = dp[i+1][j-1] + 2;//i到j的字符串长度大于2,那么i到j的最长回文长度就等于其内部最长回文子串长度加2
- }else{//如果不相等,删掉一边的字符,两种情况取最大值
- dp[i][j] = Math.max(dp[i+1][j],dp[i][j-1]);
- }
- }
- }
- // for(int i = 0; i < len; i++) {
- // for(int j = 0; j < len; j++) {
- // System.out.print(dp[i][j] + " ");
- // }
- // System.out.println();
- // }
- return dp[0][len - 1];
-
- }
- }
这两道题都是回文子串问题,不过第一个是求回文子串的个数,第二个是求最长回文子串的长度。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。