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);
}