1.回文串
(1)让字符串成为回文串的最小插入次数–动归
class Solution {
public int minInsertions(String s) {
int n=s.length();
int[][] dp=new int[n][n];
dp[0][0]=0;
for(int i=n-2;i>=0;i--){
for(int j=i+1;j<n;j++){
if(s.charAt(i)==s.charAt(j)){
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];
}
}
(2)求回文子串个数–动归
class Solution {
public int countSubstrings(String s) {
int n=s.length();
boolean[][] dp=new boolean[n][n];
int ans=0;
for(int j=0;j<n;j++){
for(int i=0;i<=j;i++){
//(1)一个字符(如'a'),肯定是回文串 j-i==0
//(2)两个相等字符(如"aa")j-i==1
//(3)当前位置i和j对应的字符相等,则需判断dp[i+1][j-1]
if(s.charAt(i)==s.charAt(j) && ((j-i<2) || dp[i+1][j-1])){
dp[i][j]=true;
ans++;
}
}
}
return ans;
}
}
(3)最长回文子串–双指针
class Solution {
public String longestPalindrome(String s) {
int n=s.length();
if(n<2) return s;
int begin=0;//最长回文子串起始位置
int maxLen=1;//最长回文子串最大长度
char[] c=s.toCharArray();
for(int j=0;j<n;j++){
for(int i=0;i<=j;i++){
if(j-i+1>maxLen && isPalindrome(c,i,j)){
begin=i;
maxLen=j-i+1;
}
}
}
return s.substring(begin,begin+maxLen);
}
// public boolean isPalindrome(String s,int left,int right){
// while(left<right){
// if(s.charAt(left)!=s.charAt(right)){
// return false;
// }
// left++;
// right--;
// }
// return true;
// }
public boolean isPalindrome(char[] c,int left,int right){
while(left<right){
if(c[left]!=c[right]){
return false;
}
left++;
right--;
}
return true;
}
}
转化成字符数组进行回文子串的判断比直接使用字符串进行单个字符的对比进行判断要快很多。
(4)最长回文串
class Solution {
public int longestPalindrome(String s) {
//统计每个字符个数,ASCII共有128个字符
int[] count=new int[128];
int n=s.length();
char[] c=s.toCharArray();
for(char ch:c){
count[ch]++;
}
//计算最长回文串长度
int res=0;
for(int v:count){
res+=v/2*2;
if(v%2==1 && res%2==0){
res++;
}
}
return res;
}
}
官方题解:
可以将每个字符使用偶数次,使得它们根据回文中心对称。
在这之后,如果有剩余的字符,可以再取出一个,作为回文中心。
对于每个字符 ch,假设它出现了 v 次,我们可以使用该字符 v / 2 * 2 次,在回文串的左侧和右侧分别放置 v / 2 个字符 ch,其中 / 为整数除法。
例如若 “a” 出现了 5 次,那么我们可以使用 “a” 的次数为 4,回文串的左右两侧分别放置 2 个 “a”。
如果有任何一个字符 ch 的出现次数 v 为奇数(即 v % 2 == 1),那么可以将这个字符作为回文中心,注意只能最多有一个字符作为回文中心。
在代码中,我们用 ans 存储回文串的长度,由于在遍历字符时,ans 每次会增加 v / 2 * 2,因此 ans 一直为偶数。但在发现了第一个出现次数为奇数的字符后,我们将 ans 增加 1,这样 ans 变为奇数,在后面发现其它出现奇数次的字符时,我们就不改变 ans 的值了。