持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情
动态规划(Dynamic Programming)是一种分阶段求解决策问题的数学思想,它通过把原问题分解为简单的子问题来解决复杂问题。
最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd" 输出:"bb"
暴力解法
穷举字符串s的所有子串,然后遍历这些子串保存最长的回文串。
fun longestPalindrome(s: String): String {
var result = ""
var max = 0
val len = s.length
for (i in 0 until len) {
for (j in i + 1..len) {
val curr = s.substring(i, j)
//isPalindromic()方法判断当前字符串是不是回文串
if (isPalindromic(curr) && curr.length > max) {
result = s.substring(i, j)
max = Math.max(max, result.length)
}
}
}
return result
}
复杂度分析
- 时间复杂度:O(n³),首先穷举子串需要两层 for 循环,循环里边判断是否为回文还需要一次循环,所以时间复杂度为 O(n³)。
- 空间复杂度:O(1)。
动态规划
由于是找回文子串,所以会有一个开始位置start,结束位置end,我们定义一个二维数组dp,dp[start][end]=true表示s[start-end]是回文串,反之不是回文串。
对于长度为1的子串,它一定是一个回文串,对于长度大于等于2的子串,先判断start位置字符和end位置字符是否一致,不一致则不是回文串,否则继续判断start+1位置和end-1位置的字符,直到start和end相遇。
public String longestPalindrome(String s) {
int len = s.length();
if (len < 2) {
return s;
}
int maxLen = 1;
int begin = 0;
boolean[][] dp = new boolean[len][len];
for (int i = 0; i < len; i++) {
dp[i][i] = true;
}
char[] charArray = s.toCharArray();
for (int left = 2; left <= len; left++) {
for (int start = 0; start < len; start++) {
int end = left + start - 1;
if (end >= len) {
break;
}
if (charArray[start] != charArray[end]) {
dp[start][end] = false;
} else {
if (end - start < 3) {
dp[start][end] = true;
} else {
dp[start][end] = dp[start + 1][end - 1];
}
}
if (dp[start][end] && end - start + 1 > maxLen) {
maxLen = end - start + 1;
begin = start;
}
}
}
return s.substring(begin, begin + maxLen);
}
}
复杂度分析
- 时间复杂度:O(n^2)
- 空间复杂度:O(n^2),需要一个二维dp数组