Problem:Finding the longest palindromic substring.
palindromic substring即正讀和反讀都一樣的字符串
思路一(代碼在下面):
- 列表內容遍歷字符串,把字符串中的每個非連續重複字符當做中心字符 c
(如果存在連續重複的字符,把這幾個字符作爲中心字符串 c, 如:”abccccd”中的”cccc”) - 比較這個中心字符或字符串的左一字符left和右一字符right爲否一致
- 如果一致,比較左二字符與右二字符直到l和r不一致
O(n)的時間複雜度
O(n)的空間複雜度(遞歸)
在吃午飯的時候在思考第一種方法,但當時被取出重複的字符難住了,當時突然覺得用stack應該會很簡單,之後又寫了第二種棧方法
思路二:
- 選出中間的字符或中間字符串
- 建一個stack,存入字符串的起始到中間字符
- IF 中間字符和之後幾個字符連續重複,
則把這幾個重複的字符擴展到子字符串
ELSE 則只把它擴展到子字符串 - 把中間字符出棧
比較中間字符的下一個非重複字符與stack.pop()比較
IF 相等
把stack.pop()擴展到子字符串的首和尾
ELSE 輸出結果O(n*n)的時間複雜度
(三)Naive Approach
we can simply examine every substring and check if it is palindromic. The time complexity is O(n^3).
(四)Dynamic Programming
動態規劃算法wiki
動態規劃常常適用於有重疊子問題[1]和最優子結構性質的問題,動態規劃方法所耗時間往往遠少於樸素解法。
思路:
* 1.dp[i][j]表示從i到j的字符串是否是迴文串
* 迴文賦true,否則賦false
* i = j,單個字符,迴文
* i > j,空串,迴文
* 2.令k = j - i爲動態算法中的狀態增量
* 把dp[i][j]的1.中已知結果記錄到二維數組中
* dp[i][j]的結果取決於dp[i + 1][j - 1]的結果
* 且如果dp[i][j] = true,則此字符串長度 k + 1
關於動態規劃算法的經典問題請看01揹包問題的java實現
(五)A Simple Algorithm
此方法與我上面寫的方法一類似,但是更加合理以及簡潔。
區別:
1.在方法伊始就進行了字符串的空串以及只有一個字符的字符串的判定
2.把方法一中的連續重複字符判定方法結合在了isLeftEqlRight方法裏,並且此方法也更加簡潔。
3.Time O(n^2), Space O(1)
代碼
思路一:
String str = "abbaddabbabcccba";
char[] cha = str.toCharArray();
// 連續重複字符的最左邊字符
int left = 0;
// 連續重複字符的最右邊字符
int right = 0;
@Test
public void findLongest(){
String destStr= cha[0] + "";
for (int i = 0; i < cha.length; i++) {
left = i;
right = isCenterStr(i);
destStr = isLeftEqlRight(right, left, destStr);
}
System.out.println(destStr);
}
/**
* 比較這個中心字符或字符串的左一字符left和右一字符right爲否一致
* 一致左二和右二繼續比較直至不一樣
*/
private String isLeftEqlRight(int right, int left,String destStr) {
System.out.println();
if (left > 0 && right < str.length() - 1&&(cha[left - 1] == cha[right + 1] )) {
left--;
right++;
return isLeftEqlRight(right, left,destStr);
}else {
if (right - left > destStr.length()) {
StringBuilder dest = new StringBuilder();
dest.append(str,left,right + 1);
destStr = dest.toString();
}
}
return destStr;
}
/**
* 判斷是否有連續重複字符
* if yes
* return 此連續字符的最後一個字符的位置
*/
public int isCenterStr(int i){
if (i == cha.length - 1 || cha[i] != cha[i + 1]) {
return i;
}
if (cha[i] == cha[i + 1]) {
i++;
right = isCenterStr(i);
}
return right;
}
output:
abbaddabba
思路二(stack方式):
String str = "abbaddabbabcccbada";
char[] cha = str.toCharArray();
@Test
public void findLongest(){
String subStr = cha[0] +"";
/**
* i爲中間字符
*/
for (int i = 4; i < cha.length;i++) {
int j = i;
Stack<Character> stack = new Stack<Character>();
StringBuilder deStr = new StringBuilder();
for (int k = 0; k <= i; k++) {
stack.push(cha[k]);
}
if (j == cha.length - 1) {
continue;
}
while (stack.peek().equals(cha[j + 1])) {
boolean flag = true;
if (flag) {
deStr.append(stack.peek());
flag = false;
}
deStr.append(cha[j + 1]);
if (j < cha.length - 1) {
j++;
}else{
break;
}
}
stack.pop();
while (stack.peek().equals(cha[j + 1])) {
deStr.append(stack.peek());
deStr.insert(0,stack.peek());
stack.pop();
if (j < cha.length - 2&&!stack.isEmpty()) {
j++;
}else{
break;
}
}
if (deStr.length() > subStr.length()) {
subStr = deStr.toString();
}
}
System.out.println(subStr);
}