迴文串
“迴文串”是一個從左讀和從右讀都一樣的字符串,比如“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的平方)的算法。
動態規劃:分解成小問題,並且使用額外的輔助空間來完成最最優解的保存。
- public int getLongestPalindrome(String s, int n) {
- // write code here
- if(s==null||n<=0){
- return 0;
- }
- // 字符串長度爲1,則其是迴文串
- if(n==1){
- return 1;
- }
- // 動態規劃中,用於保存最長迴文串的值,比如pair[0][1]表示從0-1的迴文串長度,數組值爲0表示不是迴文串
- int[][] pair = new int[n][n];
- int max=0; // 需要維護的max變量
- for(int i=0;i<n;i++){
- for(int j=0;j<=i;j++){
- // 從前往後計算是否需要更新pair數組
- // 當字符相等時,有兩種情況需要更新pair數組:
- // (1)這兩個字符是挨着的,即i-j<2;
- // (2)這兩個字符中間的字符串是迴文串,即pair[j+1][i-1]>0
- if(s.charAt(i)==s.charAt(j)&&(i-j<2||pair[j+1][i-1]>0)){
- pair[j][i]=i-j+1;
- // 判斷是否需要更新max變量
- if(pair[j][i]>max){
- max=pair[j][i];
- }
- }
- }
- }
- return max;
- }
LeetCode原題:需要的不是最長的迴文串長度,而是讓你輸出最長的迴文串(連續),則我們在更新max變量的時候,必須一併將其pair數組的兩個下標保存,最後根據start和end變量來截取原字符串,輸出最長迴文子串
- public String longestPalindrome(String s) {
- // write code here
- int len = s.length();
- if(s==null||len<=0){
- return null;
- }
- if(len==1){
- return s;
- }
- int[][] pair = new int[len][len];
- int max = 0;
- int start = 0;
- int end = 0;
- for(int i=0;i<len;i++){
- for(int j=0;j<=i;j++){
- if(s.charAt(i)==s.charAt(j)&&(i-j<2||pair[j+1][i-1]>0)){
- pair[j][i]=i-j+1;
- if(pair[j][i]>max){
- max=pair[j][i];
- start = j;
- end = i;
- }
- }
- }
- }
- return s.substring(start,end+1);
- }
題目3:給你一個字符串,可在任意位置添加字符,最少再添加幾個字符,可以使這個字符串成爲迴文字符串。
解題思路:
同上題,插入數與刪除數是一樣的,都是原字符串長度-與逆序串的最長公共子序列長度。
該算法的核心是求最長公共子序列,最長公共子序列有DP的求法,算法的複雜度是 時間和空間都是 O(n^2)
若已知原字符串與最長公共子序列,若要求最後的迴文串,如何添加字符?
如:原字符串:AB1EF2GHI1CD
最長公共子序列:121
添加步驟:以最長公共子序列爲“皮”,一層一層往下剝。
左邊:左順序+右逆序;右邊:右順序+左逆序