1、题目(leetcode第5题)
2、方法一:动态规划
(1)解题过程和思路
刚看到这题目的时候我一开始想到的就是动态规划,在解题过程中,按照动态规划的定义和解题过程我们应该根据题目示例和题目给出的定义写出动态规划的状态转移方程。
根据题目我们可以知道回文子串就是不管是从前面开始读和从后面开始读子串都是一模一样的。因此我们可以知道,如果我们删掉回文子串的头和尾两个元素则剩下的部分仍然是回文子串,比如“abcba”,删除头和尾的“a”剩下的“bcb”仍然是回文子串。即回文子串的子串仍然是回文子串。此外当子串中只有一个元素是它一定是回文子串,如“a”、“f”均为回文子串。
因此我们可以根据上面得出的结论来写出回文子串动态规划的状态转移方程:
根据状态转移方程和边界条件可以列出表格来手动模拟的动态规划解决问题的过程(以“ddcdcd”为例):
(2)具体代码实现
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size();
vector<vector<int>>dp(n, vector<int>(n));
int maxLebgth = 0;//用来记录最长回文子串的长度
int begin = 0;//用来记录回文子串开始的下标
if(n<2)
{
return s;
}
for (int i = 0; i < n; i++)
dp[i][i] = 1;
maxLenbgth=1;//单个元素的回文子串的长度为一
//根据状态转移方程写出代码
for (int j = 1; j < n; j++)
{
for (int i = 0; i < j; i++)
{
if (s[i] != s[j])
dp[i][j] = 0;
else
{
if (j - i <= 2)
{
dp[i][j] = 1;
}
else
{
dp[i][j] = dp[i + 1][j - 1];
}
}
if (dp[i][j] && j - i + 1 > maxLebgth)//更新回文子串的信息
{
maxLebgth = j - i + 1;
begin = i;
}
}
}
return s.substr(begin, maxLebgth);//根据最长回文子串的信息截断字符串s
}
};
3、方法二:中心扩散
(1)解题思路和过程
在使用动态规划提交通过后我发现虽然通过了但是空间复杂度有点高,我就去翻了一下leetcode里面的题解,发现这个题目还可以使用中心扩散法,这个方法的时间复杂度和动态规划一样都是n的平方,但是它的空间复杂度为O(1),动态规划的为O(n)。
中心扩散的方法主要是使用双指针,一个为左指针left,一个为右指针right。使用该方法的时候要注意,这里要分为两种情况,一种是回文子串的长度为奇数,另一张是回文子串的长度为偶数。
中心扩散的主要思想:当左右指针所指元素相同时,向外扩散即:letf指针向左移,right指针向右移,当左右指针所指元素不相同或者left<0或者right>字符串长度的时候停止扩散,最后返回子串开始的位置(left+1)以及子串的长度。
(2)具体代码实现
class Solution {
public:
void Funtion(vector<int>& nums, string s, int left, int right)
{
while (left >= 0 && left < s.size() && s[left] == s[right])
{
//当左右指针所指元素相等,并且左右指针均合法时
//左指针左移一位,右指针右移一位
left--;
right++;
}
//将回文子串的开始位置和结束位置保存在数组中
nums[0] = left + 1;
nums[1] = right - 1;
}
string longestPalindrome(string s) {
vector<int>nums1(2);
vector<int>nums2(2);
int begin = 0;//用于记录最长回文子串的开始下标
int maxLength = 0;//用于记录最长回文子串的长度
//循环整个s字符串
for (int i = 0; i < s.size(); i++)
{
Funtion(nums1, s, i, i);//回文串长度为奇数时操作
Funtion(nums2, s, i, i + 1);//回文串长度为偶数时操作
if (nums1[1] - nums1[0]+1 > maxLength)
{
begin = nums1[0];
maxLength = nums1[1] - nums1[0] + 1;
}//更新maxLength的值
if (nums2[1] - nums2[0] + 1 > maxLength)
{
begin = nums2[0];
maxLength = nums2[1] - nums2[0] + 1;
}//更新maxLength的值
}
return s.substr(begin, maxLength);
}
};
4、注意
在写代码时,大家一定要注意循环的次数,以及注意一下字符串截断函数substr( )的使用。