找出字符串中对称的子字符串的最大长度(最长回文)

背景:

所谓对称子字符串,就是这个子字符串要么是以其中一个词对称:比如 “aba”, “abcba”;要么就完全对称:比如"abba", "abccba"。

问题:

给你一个字符串,找出该字符串中对称的子字符串的最大长度。

思路:

首先,我们用字符数组 char[] array 来保持这个字符串,假设现在已经遍历到第 i 个字符,要找出以该字符为“中心”的最长对称字符串,我们需要用另两个指针分别向前和向后移动,直到指针到达字符串两端或者两个指针所指的字符不相等。因为对称子字符串有两种情况,所以需要写出两种情况下的代码:

1. 第 i 个字符是该对称字符串的真正的中心,也就是说该对称字符串以第 i 个字符对称, 比如: “aba”。代码里用 index 来代表 i.

	public static int maxLengthMiddle(char[] array, int index) {
		int length = 1; //最长的子字符串长度
		int j = 1; //前后移动的指针
		while ((array[index - j] == array[index + j]) && (index - j) >= 0 && array.length > (index + j)) {
			length += 2;
			j++;
		}
		
		return length;
	}

2. 第 i 个字符串是对称字符串的其中一个中心。比如“abba”。

	public static int maxLengthMirror(char[] array, int index) {
		int length = 0; //最长的子字符串长度
		int j = 0; //前后移动的指针
		while ((array[index - j] == array[index + j + 1]) && (index - j) >= 0 && array.length > (index + j + 1)){
			length += 2;
			j++;
		}
		
		return length;
	}

有了这样两个函数,我们只需要遍历字符串里所有的字符,就可以找出最大长度的对称子字符串了。

	public static int palindrain(char[] array) {
		if (array.length == 0) return 0;
		int maxLength = 0;
		for (int i = 0; i < array.length; i++) {
			int tempMaxLength = - 1;
			int length1 = maxLengthMiddle(array, i);
			int length2 = maxLengthMirror(array, i);
			tempMaxLength = (length1 > length2) ? length1 : length2;
			if (tempMaxLength > maxLength) {
				maxLength = tempMaxLength;
			}
		}
		return maxLength;
	}

因为找出以第 i 个字符为“中心”对称字符串复杂度为 O(N),所以整个算法的复杂度为O(N^2)。

这里有另一种方法算法,复杂度是一样,但是,看起来更简洁一点。

public class Palindrome {

	public static void main(String[] args) {
		Palindrome pld = new Palindrome();
		System.out.println(pld.longestPalindrome("abcc"));
	}
	
	String getPalindrome(String s, int l, int r) {
		int n = s.length();
		while (l >= 0 && r <= n-1 && s.charAt(l) == s.charAt(r)) {
			l--;
			r++;
		}
		return s.substring(l + 1, r);
	}
		 
	String longestPalindrome(String s) {
		int n = s.length();
		if (n == 0) return "";
		String longest = s.substring(0, 1); 
		for (int i = 0; i < n-1; i++) {
			String p1 = getPalindrome(s, i, i);
			if (p1.length() > longest.length()) {
				longest = p1;
			}
				 
			String p2 = getPalindrome(s, i, i+1);
			if (p2.length() > longest.length()) {
				longest = p2;
			}
		}
		return longest;
	}
}

有一种可以把复杂度降到O(N)的算法,但是这个算法要利用 suffix tree, 有兴趣的可以搜索一下。


参考:http://www.leetcode.com/2011/11/longest-palindromic-substring-part-i.html
转载请注明出处:http://blog.csdn.net/beiyeqingteng


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 回文串是指正着读和倒着读都一样的字符串。要求找出一个字符串最长回文串。 解决这个问题的方法有很多,其一种比较简单的方法是暴力枚举。具体来说,我们可以枚举所有可能的串,然后判断每个串是否是回文串,最后找出最长回文串。 具体实现时,我们可以从字符串的第一个字符开始,依次枚举所有可能的串。对于每个串,我们可以使用双指针法来判断它是否是回文串。具体来说,我们可以使用两个指针分别指向串的首尾字符,然后依次向间移动,判断对应的字符是否相等。如果所有字符都相等,那么这个串就是回文串。 在判断完所有串之后,我们就可以找出最长回文串了。具体来说,我们可以用一个变量来记录当前找到最长回文串的长度,以及它的起始位置。在枚举所有串的过程,如果找到了一个更长的回文串,那么就更新这个变量。 需要注意的是,由于字符串可能存在偶数长度回文串,因此我们需要分别枚举以每个字符为心的奇数长度回文串和以每两个相邻字符为心的偶数长度回文串。 这种暴力枚举的方法时间复杂度为O(n^3),其n是字符串长度。虽然时间复杂度比较高,但是这种方法比较简单易懂,可以作为其他更高效的算法的基础。 ### 回答2: 回文串是指正着读和倒着读一样的字符串。例如,'level'和'noon'就是回文串。编写程序来寻找给定字符串最长回文串。 一种常见的方法是暴力枚举字符串的所有串并检查它们是否是回文。这种方法的时间复杂度为O(n^3),不适用于长字符串。另一种常见的方法是动态规划。这种方法的时间复杂度为O(n^2),适用于较长的字符串。 动态规划方法的主要思路如下: 1.定义状态:dp[i][j]表示从i到j的串是否为回文。 2.初始化状态:对于所有i,dp[i][i]都是true。 3.状态转移:当s[i] = s[j]时,如果dp[i+1][j-1]是true,那么dp[i][j]也是true。 4.记录最长回文串的起始位置和长度:遍历dp数组,找到值为true且长度最大串即可。 下面是一个Python实现的例: ```python def longest_palindrome(s:str) -> str: if not s: # 处理输入为空的情况 return "" n = len(s) dp = [[False] * n for _ in range(n)] # 初始化dp数组 start, max_len = 0, 1 # 记录最长回文串的起始位置和长度 for i in range(n): # 初始化对角线上的状态 dp[i][i] = True for j in range(1, n): for i in range(0, j): if s[i] == s[j]: if j - i < 3: # 特判长度小于3的情况 dp[i][j] = True else: dp[i][j] = dp[i+1][j-1] else: dp[i][j] = False if dp[i][j]: # 记录最长回文串的起始位置和长度 if j - i + 1 > max_len: max_len = j - i + 1 start = i return s[start:start+max_len] ``` 该算法的时间复杂度为O(n^2),空间复杂度也为O(n^2)。 ### 回答3: 回文串指正着读和倒着读都一样的字符串,例如 "level", "noon" 等。在一个字符串,可能不存在回文串,也可能存在多个长度相同的回文串。现在给定一个字符串,需要我们求出其最长回文串。 解决此问题,可以用动态规划算法。假设字符串长度为 n,定义一个二维数组 dp (n * n),其 dp[i][j] 表示从 i 到 j 这一段字符串是否为回文串。当字符串为空或长度为 1 时,皆为回文串(即 dp[i][i] = true)。当字符串长度大于等于 2 时,若第 i 个字符和第 j 个字符相等,且从 i + 1 到 j - 1 的字符串也是回文串,那么从 i 到 j 的字符串也是回文串(即 dp[i][j] = dp[i + 1][j - 1] && s[i] == s[j])。此外,记录回文串的起始位置和长度,最终找到最长回文串即可。 以下是 Python 代码实现: ``` class Solution: def longestPalindrome(self, s: str) -> str: n = len(s) dp = [[False] * n for _ in range(n)] res = "" for i in range(n - 1, -1, -1): for j in range(i, n): dp[i][j] = s[i] == s[j] and (j - i < 3 or dp[i + 1][j - 1]) if dp[i][j] and j - i + 1 > len(res): res = s[i:j+1] return res ``` 时间复杂度为 O(n^2),空间复杂度为 O(n^2)。总的来说,动态规划算法是解决最长回文串问题的一种行之有效的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值