1. LeetCode 5. 最长回文子串(求长度)
题目: 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设s 的最大长度为 1000。
输入: “babad”
输出: “bab” 注意: “aba” 也是一个有效答案。
假设字符串s的长度为length,建立一个length*length的矩阵dp。令 dp[i][j] 表示 S[i] 至 S[j] 所表示的子串是否是回文子串。
- 当 i == j,dp[i][j] 是回文子串(单字符都是回文子串);
- 当 j - i < 3,只要 S[i] == S[j],则 dp[i][j] 是回文子串(如"aa",“aba”),否则不是;
- 当 j - i >= 3,如果 S[i] == S[j] && dp[i+1][j-1] ,则 dp[i][j] 是回文子串,否则不是 。
需要注意的点是,因为要访问dp[i+1][j-1],因此 i 是从大到小的,j是从小到大的。
public String longestPalindrome(String s) {
int len = s.length();
if (len == 0) return "";
boolean[][] dp = new boolean[len][len];
int left = 0, right = 0, ans = 0;// left right 记录最长的回文子串起始索引
for (int i = len - 1; i >= 0; --i) {
dp[i][i] = true;
for (int j = i + 1; j < len; ++j) {
if (s.charAt(i) == s.charAt(j)) {
if (j - i < 3)
dp[i][j] = true;
else
dp[i][j] = dp[i + 1][j - 1];
}
if (dp[i][j] == true && j - i > right - left) {
right = j;
left = i;
}
}
}
return s.substring(left, right + 1);
}
时间空间都是 O(n*n); 马拉车算法是O(n) 。
不用考虑dp[i + 1][j - 1
] 的索引越界的情况,因为只有两种情况会越界:
i =len-1
或者 j=0
;
-
当
i=len-1
时,j=i,
也从len-1
开始,但是 if里第一个条件j-i<=2
已经满足,不会访问dp[i+1],
而且j层的循环只执行一次(j++之后等于len)就退出了。 -
当
j=0
时,因为j从i开始增大
,所以i
也是0,同样 if 的第一个条件也满足了。
2. LeetCode 647. 回文子串(求个数)
题目:给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。
示例 1: 输入: “abc” 输出: 3
解释: 三个回文子串: “a”, “b”, “c”.
示例 2: 输入: “aaa” 输出: 6
说明: 6个回文子串: “a”, “a”, “a”, “aa”, “aa”, “aaa”.
方法1. 中心扩展
int countSubstrings(string s) {
int ans = 0;
for (int i = 0; i < s.length(); ++i) {
ans += helper(s, i, i); //以当前点i位置,向两边扩展
ans += helper(s, i, i + 1);// 以i i+1位置向两边扩展
}
return ans;
}
int helper(string s, int<