回文串题目总结

回文串

“回文串”是一个从左读和从右读都一样的字符串,比如“level”或者“noon”等等就是回文串。 

常见的回文串有:dad,123454321,123456654321….

题目1:判断一个字符串是否为回文串

递归法:

public static boolean check(String str) {
  if ( str.charAt(0) != str.charAt(str.length() - 1) ) {
  return false;
  }

  if (str.length() <= 1) {
  return true;
  }
//可改成if...else if....else

  return check(str.substring(1, str.length() - 1));//切割两端,将子串递归调用

}
循环法:

public boolean isPalindromeNumber(long num){  
        String str = num + "";  
        int start = 0;  
        int end = str.length() - 1;  
        while(start <= end){  
            char s = str.charAt(start);  
            char e = str.charAt(end);  
            if(s != e){  
                return false;  
            }else{  
                start++;  
                end--;  
            }  
        }  
        return true;  
}  



题目2:给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?

 输出需要删除的字符个数。

解题思路:动态规划 :分解成小问题,并且使用额外的辅助空间来完成最最优解的保存。

提到回文串,自然要利用回文串的特点,想到将源字符串逆转后,“回文串”(不一定连续)相当于顺序没变
 求原字符串和其反串的最大公共子序列(不是子串,因为可以不连续)的长度(使用动态规划很容易求得),
 然后用原字符串的长度减去这个最大公共子串的长度就得到了最小编辑长度。

public class PalindromicSubstring {
	
	public static void main(String[] args) {
		// System.out.println("请输入");
		Scanner sc = new Scanner(System.in);
		while (sc.hasNext()) {
			String s1 = sc.next();
			String s2 = new StringBuilder(s1).reverse().toString();
			int[][] dp = new int[s1.length() + 1][s2.length() + 1];
			for (int i = 1; i < dp.length; i++) {
				for (int j = 1; j < dp[0].length; j++) {
					dp[i][j] = s1.charAt(i - 1) == s2.charAt(j - 1) ? dp[i - 1][j - 1] + 1
							: Math.max(dp[i - 1][j], dp[i][j - 1]);
				}
			}
			System.out.println(s1.length() - dp[s1.length()][s2.length()]);
		}
	}
}

算法矩阵
    G A A T T C A G T T A
  0 0 0 0 0 0 0 0 0 0 0 0
G 0 1 1 1 1 1 1 1 1 1 1 1
G 0 1 1 1 1 1 1 1 2 2 2 2
A 0 1 2 2 2 2 2 2 2 2 2 2
T 0 1 2 2 3 3 3 3 3 3 3 3
C 0 1 2 2 3 3 4 4 4 4 4 4
G 0 1 2 2 3 3 3 4 5 5 5 5
A 0 1 2 3 3 3 3 4 5 5 5 6

参考文章 http://www.cnblogs.com/grenet/archive/2010/06/03/1750454.html

若是要求连续:求两个字符串的最长公共连续子串长度。代码如下:

import java.util.Scanner;

public class LongestComSubString {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		String s1 = in.next();
		String s2 = in.next();
		char[] c1 = s1.toCharArray();
		char[] c2 = s2.toCharArray();

		int max = 0;
		int[][] matrix = new int[c1.length + 1][c2.length + 1]; // 定义2维数组
		for (int i = 1; i < matrix.length; i++) {
			for (int j = 1; j < matrix[i].length; j++) {
				if (c1[i - 1] == c2[j - 1]) { // 横向字符与纵向字符相同的时候
					matrix[i][j] = matrix[i - 1][j - 1] + 1; // 该位置的值等于上个对角位置的值加1
					if (matrix[i][j] > max) {// 跟踪最大值
						max = matrix[i][j];
					}
				}
			}
		}
		System.out.println(max);
	}
}

由上可知:若可以不连续:
dp[i][j] = s1.charAt(i - 1) == s2.charAt(j - 1) ? dp[i - 1][j - 1] + 1: Math.max(dp[i - 1][j], dp[i][j - 1]);

若要求连续:

matrix[i][j] = matrix[i - 1][j - 1] + 1; 

法二:


       对于一个字符串,请设计一个高效算法,计算其中最长连续回文子串的长度。给定字符串A以及它的长度n,请返回最长回文子串的长度。


思路:

本题使用暴力破解法,时间复杂度为O(N的立方),我们先看一种使用动态规划,使得时间复杂度降为了O(N的平方)的算法。

动态规划:分解成小问题,并且使用额外的辅助空间来完成最最优解的保存

[java]  view plain  copy
  1. public int getLongestPalindrome(String s, int n) {  
  2.             // write code here  
  3.             if(s==null||n<=0){  
  4.                 return 0;  
  5.             }  
  6.             // 字符串长度为1,则其是回文串  
  7.             if(n==1){  
  8.                 return 1;  
  9.             }  
  10.             // 动态规划中,用于保存最长回文串的值,比如pair[0][1]表示从0-1的回文串长度,数组值为0表示不是回文串  
  11.             int[][] pair = new int[n][n];  
  12.             int max=0;  // 需要维护的max变量  
  13.               
  14.             for(int i=0;i<n;i++){  
  15.                 for(int j=0;j<=i;j++){  
  16.                     // 从前往后计算是否需要更新pair数组  
  17.                     // 当字符相等时,有两种情况需要更新pair数组:  
  18.                     // (1)这两个字符是挨着的,即i-j<2;  
  19.                     // (2)这两个字符中间的字符串是回文串,即pair[j+1][i-1]>0  
  20.                     if(s.charAt(i)==s.charAt(j)&&(i-j<2||pair[j+1][i-1]>0)){  
  21.                         pair[j][i]=i-j+1;  
  22.                         // 判断是否需要更新max变量  
  23.                         if(pair[j][i]>max){  
  24.                             max=pair[j][i];  
  25.                         }  
  26.                     }  
  27.                 }  
  28.             }  
  29.             return max;  
  30.         }  

LeetCode原题:需要的不是最长的回文串长度,而是让你输出最长的回文串(连续),则我们在更新max变量的时候,必须一并将其pair数组的两个下标保存,最后根据start和end变量来截取原字符串,输出最长回文子串

[java]  view plain  copy
  1. public String longestPalindrome(String s) {  
  2.              // write code here  
  3.              int len = s.length();  
  4.                 if(s==null||len<=0){  
  5.                     return null;  
  6.                 }  
  7.                 if(len==1){  
  8.                     return s;  
  9.                 }  
  10.                 int[][] pair = new int[len][len];  
  11.                 int max = 0;  
  12.                 int start = 0;  
  13.                 int end = 0;  
  14.                 for(int i=0;i<len;i++){  
  15.                     for(int j=0;j<=i;j++){  
  16.                         if(s.charAt(i)==s.charAt(j)&&(i-j<2||pair[j+1][i-1]>0)){  
  17.                             pair[j][i]=i-j+1;  
  18.                             if(pair[j][i]>max){  
  19.                                 max=pair[j][i];  
  20.                                 start = j;  
  21.                                 end = i;  
  22.                             }  
  23.                         }  
  24.                     }  
  25.                 }  
  26.                 return s.substring(start,end+1);  
  27.         }  


题目3:给你一个字符串,可在任意位置添加字符,最少再添加几个字符,可以使这个字符串成为回文字符串。

解题思路:
同上题,插入数与删除数是一样的,都是原字符串长度-与逆序串的最长公共子序列长度。
该算法的核心是求最长公共子序列,最长公共子序列有DP的求法,算法的复杂度是 时间和空间都是 O(n^2)

若已知原字符串与最长公共子序列,若要求最后的回文串,如何添加字符?

如:原字符串:AB1EF2GHI1CD

       最长公共子序列:121

添加步骤:以最长公共子序列为“皮”,一层一层往下剥。

               左边:左顺序+右逆序;右边:右顺序+左逆序

            


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值