动态规划(英语:Dynamic programming,简称 DP)是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。
动态规划常常适用于有重叠子问题和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。
dp算法有两个要点,1是状态转移方程,2是中间结果的记录。
详细解释
q5_最长回文子串
思路1
暴力求解,遍历所有的子串,然后依次判断是不是回文,找到最长的回文。
复杂程度太高,效率极差,代码就不贴了。
思路2
动态规划
代码
public String longestPalindrome2(String s) {
int len = s.length();
if (len <= 1) {
return s;
}
//pass[i][j] 表示s的子串 [i,j]是否是回文
//状态转移方程 pass[i][j]= s[i]==s[j] && pass[i+1][j-1]
boolean[][] pass = new boolean[len][len];
char[] chars = s.toCharArray();
int start = 0;
int maxLen = 1;
for (int i = 0; i < len; i++) {
pass[i][i] = true;
}
for (int j = 1; j < len; j++) {
for (int i = 0; i < j; i++) {
if (chars[i] != chars[j]) {
pass[i][j] = false;
} else {
if (j - i <= 2) {
pass[i][j] = true;
} else {
//外层循环是j++,所以在此之前,一定已经给pass[0到j][j-1]赋值了
pass[i][j] = pass[i + 1][j - 1];
}
}
if (pass[i][j] && j - i + 1 > maxLen) {
start = i;
maxLen = j - i + 1;
}
}
}
return s.substring(start, start + maxLen);
}
思路3
中心扩散
代码
public String longestPalindrome3(String s) {
if (s.length() <= 1) {
return s;
}
String ans = "";
for (int i = 0; i < s.length() - 1; i++) {
ans = maxStr(ans, spread(s, i, false));
ans = maxStr(ans, spread(s, i, true));
}
return ans;
}
private String maxStr(String s1, String s2) {
if (s1.length() >= s2.length()) {
return s1;
}
return s2;
}
private String spread(String s, int center, boolean even) {
int left = center;
int right = center;
if (even) {
right = center + 1;
}
while (left >= 0 && right < s.length()) {
if (s.charAt(left) == s.charAt(right)) {
left--;
right++;
} else {
break;
}
}
return s.substring(left + 1, right);
}
实际执行结果,中心扩散优于动态规划
思路4
封神的马拉车算法,思路2和3,复杂度都是O(n²),马拉车可以把复杂度降到O(n)。
马拉车具体怎么拉?
代码
public String longestPalindrome4(String s) {
char space = '#';
char header = '^';
char tail = '$';
StringBuilder sb = new StringBuilder();
sb.append(header).append(space);
int len = s.length();
for (int i = 0; i < len; i++) {
sb.append(s.charAt(i)).append(space);
}
sb.append(tail);
String newS = sb.toString();
int p[] = new int[newS.length()];
int left, right, value;
for (int i = 1; i < newS.length() - 1; i++) {
left = i - 1;
right = i + 1;
value = 0;
while (newS.charAt(left) != tail && newS.charAt(right) != tail
&& newS.charAt(left) == newS.charAt(right)) {
left--;
right++;
value++;
}
p[i - 1] = value;
}
int maxLen = 0;
int start = 0;
for (int i = 0; i < p.length; i++) {
if (p[i] >= maxLen) {
start = i;
maxLen = p[i];
}
}
start = (start - maxLen) / 2;
return s.substring(start, start + maxLen);
}