LeetCode中等:最长回文子串

最长回文子串(C#)

题目描述:给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

1. 暴力法

思路:对所有子串遍历,判断是否为回文串。

显然需要一个函数判断一个字符串是否为回文串

public bool isPalindromic(string s)
{
	for (int i = 0; i < s.Length / 2; i++)
	{
		if (s[i] != s[s.Length - i - 1])
			return false;
	}
	return true;
}

ok,接下来进行遍历

public string LongestPalindrome(string s)
{
	string result = "";
	int MaxLength = 0;
	string current_s="";
	for (int i = 0; i < s.Length; i++)
	{
		for (int j = i; j < s.Length; j++)
		{
			current_s=s.Substring(i, j - i + 1);
			result = isPalindromic(current_s) && current_s.Length > result.Length ? current_s : result;
		}
	}
	return result;
}

简单粗暴,但是时间复杂度很高,所以提交会这样:
在这里插入图片描述
但其实结果是对的:
在这里插入图片描述

时间复杂度:两层 for 循环已经是O(n2)了,在内层循环判断是否是回文串还需要O(n),所以是O(n3)了。
空间复杂度:常数个变量所以是O(1)。

2.中心扩展算法

比较常规的,也是我看到这道题的第一种想法。

思路:一个字符串的长度只能是奇数或者偶数(废话),那么一个回文字符串也只能是奇数的或者偶数的(还是废话)。奇数回文字符串的中心是一个字符,而偶数字符串的中心是一个 间隔
我们可以通过这个中心向两边扩展,使用左右两个指针(并不是指针),每次循环先判断两个指针对应位置的值是否相等,然后左指针向左移一个位置,右指针向右移一个位置,直到两个值不相等,或者越界。一次循环结束之后,移动中心的位置,需要注意的是中心只需要移动到字符串的最后一个位置即可。
重点来了! 因为奇数串和偶数串的中心不同,所以中心每次移动都需要判断两次。向isPalindromic函数输入不同值来区分奇数串和偶数串:
1、如果传入重合的索引编码,进行中心扩散,此时得到的回文子串的长度是奇数;
2、如果传入相邻的索引编码,进行中心扩散,此时得到的回文子串的长度是偶数。
可以理解为,奇数串的时候是以输入的位置i作为中心,而偶数串的时候是以i和i+1之间作为中心,也就是上面说的那个 间隔

代码如下:

public string LongestPalindrome(string s) {
	if(s.Length<=1)
		return s;
	string result="";
	for (int i = 0; i < s.Length - 1; i++)
    {
		string oddString = isPalindromic(s, i, i);//奇数串
		string evenString = isPalindromic(s, i, i + 1);//偶数串
		if (oddString.Length>result.Length||evenString.Length>result.Length)
			result = oddString.Length > evenString.Length ? oddString : evenString;
        }
	return result;
}
public string isPalindromic(string s, int left, int right)
{
	string result="";
	while (left >= 0 && right < s.Length)
	{
		if (s[left] != s[right])
			break;
		result = right - left + 1 > result.Length ? s.Substring(left, right - left + 1) : result; 
		left--;
		right++;
	}
	return result;
}

时间复杂度:两层 for 循环所以是O(n2)
空间复杂度:常数个变量所以是O(1)。

3.动态规划法

动态规划法的做法其实和暴力法很相似,但是不使用额外的函数去判断一个字符串是否回文,而是通过一个二维数组将之前得到的子串是否回文的结果保存起来。

思路:首先,一个字符串若是回文的,那么其两端的两个字符一定相等,其次除去两端的两个字符后中间的子串也必然是回文的。
所以我们定义一个二维数组P(i,j),里面存放的是对应从位置i到j的字符串是否是回文的。
根据前面所述,P(i,j)的值为(S[i]==S[j]&&P(i+1,j−1))。但是还有一点小问题,当j-i的值小于等于2(也就是当前判断的字符串长度为0,1,2)时,P(i+1,j−1)的值是不存在的。
所以应当表述为P(i,j) = (s[i] == s[j]) && (j - i <= 2 || P(i+1,j−1))。需要注意的是j-i<=2应当放在P(i+1,j−1)前判断。由于短路或(||)的性质,当j-i<=2成立时不会对后面的P(i+1,j−1)进行判断,也就巧妙地规避了P(i+1,j−1)的值不存在的问题。

代码如下:

        public static string LongestPalindrome1(string s)
        {
            if (s.Length == 0 || s.Length == 1)
                return s;
            string result="";
            bool[,] dp = new bool[s.Length, s.Length];
            for (int right = 0; right < s.Length ; right++)
            {
                for (int left = 0; left <= right; left++)
                {
                    dp[left, right] = (s[left] == s[right]) && (right - left <= 2 || dp[left + 1, right - 1]);
                    result = dp[left, right] && (right - left >= result.Length) ? s.Substring(left, right - left + 1) : result;
                }
            }
            return result;
        }

时间复杂度:两层循环 O(n2)。
空间复杂度:用二维数组 P 保存每个子串的情况 O(n2)。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值