这是来自Algorithms book(Vazirani)的问题(6.7 ch6)与finding longest palindrome的经典问题略有不同。我该如何解决这个问题?
如果是,则子序列是回文 无论是从左到右阅读还是 右到左。例如, 序列
A,C,G,T,G,T,C,A,A,A,A,T,C,G
有很多回文子句, 包括
A,C,G,C,A
和A,A,A,A
(另一方面,子序列A,C,T
不是回文)。设计一个 采用序列x[1 ...n]
并返回(长度)的算法 最长的回文序列。它的 运行时间应为O(n^2)
答案 0 :(得分:77)
这可以使用动态编程在O(n ^ 2)中解决。基本上,问题是使用x[i...j]
,x[i+1...j]
和x[i,...j-1]
的最长子序列在x[i+1,...,j-1]
中构建最长的回文子序列(如果第一个和最后一个字母相同)。
首先,空字符串和单个字符串通常是回文。
请注意,对于子串x[i,...,j]
,如果x[i]==x[j]
,我们可以说最长回文的长度是x[i+1,...,j-1]+2
以上最长的回文。如果它们不匹配,则最长的回文数是x[i+1,...,j]
和y[i,...,j-1]
的最高回文数。
这给了我们功能:
longest(i,j)= j-i+1 if j-i<=0,
2+longest(i+1,j-1) if x[i]==x[j]
max(longest(i+1,j),longest(i,j-1)) otherwise
你可以简单地实现该函数的memoized版本,或者编写一个最长[i] [j]自下而上的表。
这只给出了最长子序列的长度,而不是实际的子序列本身。但它也可以很容易地扩展到这样做。
答案 1 :(得分:7)
此问题也可以作为称为LCS(最长公共子序列)问题的非常常见问题的变体来完成。 让输入字符串由字符数组s1 [0 ... n-1]表示。
1)反转给定的序列并将反向存储在另一个数组中,例如s2 [0..n-1],其本质上是s1 [n-1 .... 0]
2)给定序列s1和反向序列s2的LCS将是最长的回文序列。
该解决方案也是O(n ^ 2)解决方案。
答案 2 :(得分:1)
让我有点困惑的是子串和子序列之间的差异。(见Ex6.8和6.11)根据我们对子序列的理解,给出的例子没有回文子序列ACGCA。 这是我的伪代码,我不太确定初始化&gt;&lt;
for i = 1 to n do
for j = 1 to i-1 do
L(i,j) = 0
for i = 1 to n do
L(i,i) = 1
for i = n-1 to 1 do //pay attention to the order when filling the table
for j = i+1 to n do
if x[i] = x[j] then
L(i,j) = 2 + L(i+1, j-1)
else do
L(i,j) = max{L(i+1, j), L(i, j-1)}
return max L(i,j)
准备算法最终......
答案 3 :(得分:0)
最长回文序列的Java实现
public class LongestPalindrome
{
int max(int x , int y)
{
return (x>y)? x:y;
}
int lps(char[] a ,int i , int j)
{
if(i==j) //If only 1 letter
{
return 1;
}
if(a[i] == a[j] && (i+1) == j) // if there are 2 character and both are equal
{
return 2;
}
if(a[i] == a[j]) // If first and last char are equal
{
return lps(a , i+1 , j-1) +2;
}
return max(lps(a,i+1 ,j),lps(a,i,j-1));
}
public static void main(String[] args)
{
String s = "NAMAN IS NAMAN";
LongestPalindrome p = new LongestPalindrome();
char[] c = s.toCharArray();
System.out.print("Length of longest seq is" + p.lps(c,0,c.length-1));
}
}
答案 4 :(得分:0)
import java.util.HashSet;
import java.util.Scanner;
/ ** * @param args *我们得到一个字符串,我们需要在该字符串中找到最长的子序列,即回文 *在这段代码中,我们使用了hashset来确定给定字符串中唯一的子字符串集 * /
公共类NumberOfPalindrome {
/**
* @param args
* Given a string find the longest possible substring which is a palindrome.
*/
public static HashSet<String> h = new HashSet<>();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
for(int i=0;i<=s.length()/2;i++)
h.add(s.charAt(i)+"");
longestPalindrome(s.substring(0, (s.length()/2)+(s.length()%2)));
System.out.println(h.size()+s.length()/2);
System.out.print(h);
}
public static void longestPalindrome(String s){
//System.out.println(s);
if(s.length()==0 || s.length()==1)
return;
if(checkPalindrome(s)){
h.add(s);
}
longestPalindrome(s.substring(0, s.length()-1));
longestPalindrome(s.substring(1, s.length()));
}
public static boolean checkPalindrome(String s){
//System.out.println(s);
int i=0;int j=s.length()-1;
while(i<=j){
if(s.charAt(i)!=s.charAt(j))
return false;
i++;j--;
}
return true;
}
}
答案 5 :(得分:0)
private static int findLongestPalindromicSubsequence(String string) {
int stringLength = string.length();
int[][] l = new int[stringLength][stringLength];
for(int length = 1; length<= stringLength; length++){
for(int left = 0;left<= stringLength - length;left++){
int right = left+ length -1;
if(length == 1){
l[left][right] = 1;
}
else{
if(string.charAt(left) == string.charAt(right)){
//L(0, n-1) = L(1, n-2) + 2
if(length == 2){
// aa
l[left][right] = 2;
}
else{
l[left][right] = l[left+1][right-1]+2;
}
}
else{
//L(0, n-1) = MAX ( L(1, n-1) , L(0, n-2) )
l[left][right] = (l[left+1][right] > l[left][right-1])?l[left+1][right] : l[left][right-1];
}
}
}
}
return l[0][stringLength-1];
}
答案 6 :(得分:0)
程序,用于从给定的字符串中找到最长的回文子字符串。
package source;
import java.util.ArrayList;
public class LongestPalindrome
{
//Check the given string is palindrome by
public static boolean isPalindrome (String s)
{
StringBuffer sb = new StringBuffer(s);
if(s.equalsIgnoreCase(sb.reverse().toString()))
return true;
else
return false;
}
public static void main(String[] args)
{
//String / word without space
String str = "MOMABCMOMOM"; // "mom" //"abccbabcd"
if(str.length() > 2 )
{
StringBuffer sb = new StringBuffer();
ArrayList<String> allPalindromeList = new ArrayList<>();
for(int i=0; i<str.length(); i++)
{
for(int j=i; j<str.length(); j++)
{
sb.append(str.charAt(j));
if( isPalindrome(sb.toString()) ) {
allPalindromeList.add(sb.toString());
}
}
//clear the stringBuffer
sb.delete(0, sb.length());
}
int maxSubStrLength = -1;
int indexMaxSubStr = -1;
int index = -1;
for (String subStr : allPalindromeList) {
++index;
if(maxSubStrLength < subStr.length()) {
maxSubStrLength = subStr.length();
indexMaxSubStr = index;
}
}
if(maxSubStrLength > 2)
System.out.println("Maximum Length Palindrome SubString is : "+allPalindromeList.get(indexMaxSubStr));
else
System.out.println("Not able to find a Palindrome who is three character in length!!");
}
}
}
答案 7 :(得分:-1)
表示字符串中的每个字母:
将字母设置为回文的中间位置(当前长度= 1)
检查回文多长时间,如果这是它的中间
如果这个回文比我们发现的回文长(直到现在):保持索引和回文的大小。
O(N ^ 2):因为我们有一个循环选择中间和一个循环,检查回文多长时间,如果这是中间。每个循环从0到O(N)[第一个从0到N-1,第二个从0到(N-1)/ 2]
例如: D B A B C B A
i = 0:D是回文的中间,不能超过1(因为它是第一个)
i = 1:B是回文的中间,在B之前和之后检查char:不相同(一侧为D而另一侧为A) - &gt;长度是1.
i = 2:A是回文的中间,在A之前和之后检查char:B-&gt;长度为3.检查间隙为2的字符:不识别(一边为D,另一边为C) - &gt;长度是3。
等。
答案 8 :(得分:-2)
输入: A1,A2,....,An
目标:找到最长的严格增加的子序列(不一定是连续的)。
L(j):以j结尾的最长严格增加后续序列
L(j): max{ L(i)}+1 } where i < j and A[i] < A[j]
然后找max{ L(j) } for all j
您将获得源代码here