解法一:暴力解法
思路:不断枚举每一个合法的字符区间
时间复杂度:O(N³) 空间复杂度:O(1)
class Solution { fun longestPalindrome(s: String): String { if (s.length < 2) return s var maxLen = 1 var begin = 0 val chars = s.toCharArray() for (i in chars.indices) { for (j in i + 1 until chars.size) { if (j - i + 1 > maxLen && validPalindrome(chars, i, j)) { maxLen = j - i + 1 begin = i } } } return s.substring(begin, begin + maxLen) } private fun validPalindrome(chars: CharArray, i: Int, j: Int): Boolean { var left = i var right = j while (left < right) { if (chars[left] != chars[right]) return false left++ right-- } return true } }
解法二:中心扩散法
思路:枚举所有的「回文中心」并尝试「扩展」,直到无法扩展为止,此时的回文串长度即为此「回文中心」下的最长回文串长度。
时间复杂度:O(N²) 空间复杂度:O(1)
class Solution { fun longestPalindrome(s: String): String { if (s.length < 2) return s var maxLen = 1 var begin = 0 val chars = s.toCharArray() for (i in 0 until chars.size - 1) { //奇数中心 val oddLen = expandAroundCenter(chars, i, i) //偶数中心 val evenLen = expandAroundCenter(chars, i, i + 1) val curMaxLen = Math.max(oddLen, evenLen) if (curMaxLen > maxLen) { maxLen = curMaxLen //覆盖奇偶两个情况 begin = i - (maxLen - 1) / 2 } } return s.substring(begin, begin + maxLen) } private fun expandAroundCenter(chars: CharArray, i: Int, j: Int): Int { val size = chars.size var left = i var right = j while (left >= 0 && right < size) { if (chars[left] == chars[right]) { left-- right++ } else { break } } //right - left + 1 - 2 (-2是因为需要减去最后那次不匹配的情况) return right - left - 1 } }
解法三:动态规划
- 状态定义:dp[ i ][ j ]表示子串 s[ i .. j ]是否为回文子串
- 状态转移方程:dp[ i ][ j ]=( s[ i ] == s[ j ] ) and dp[ i + 1 ][ j – 1 ]
- 边界条件:
对于长度为 1 的子串,它显然是个回文串;
对于长度为 2 的子串,只要它的两个字母相同,它就是一个回文串。
dp( i , i ) = true
dp[ i , i + 1 ] = ( s[ i ] == s[ j ] )
整理后的最终状态方程:来源:Leetcode 官方
时间复杂度:O(N²) 空间复杂度:O(N²)
代码:
class Solution { fun longestPalindrome(s: String): String { if (s.length < 2) return s val len = s.length var maxLen = 1 var begin = 0 //表示 s[ i .. j ]是否是回文串 val dp = Array(len) { BooleanArray(len) { false } } for (i in s.indices) { dp[i][i] = true } val chars = s.toCharArray() //i 行 j 列 for (j in 1 until len) { for (i in 0 until j) { if (chars[i] != chars[j]) { dp[i][j] = false } else { if (j - i < 3) { dp[i][j] = true } else { dp[i][j] = dp[i + 1][j - 1] } } //只要 dp[i][j]=true,表示子串 s[i .. j]是回文,此时记录回文长度和起始位置 if (dp[i][j] && j - i + 1 > maxLen) { maxLen = j - i + 1 begin = i } } } return s.substring(begin, begin + maxLen) } }
建议配合打印与 debug 查看具体过程。
本站由以下主机服务商提供服务支持:
0条评论