Algorithm 添加最少数量的字符以生成回文
问题是: 给定任何字符串,添加尽可能少的字符,使其在线性时间内成为回文 我只能想出一个O(N2)溶液Algorithm 添加最少数量的字符以生成回文,algorithm,palindrome,Algorithm,Palindrome,问题是: 给定任何字符串,添加尽可能少的字符,使其在线性时间内成为回文 我只能想出一个O(N2)溶液 有人能帮我一个O(N)解决方案吗?我假设您不能替换或删除任何现有字符 一个好的开始是反转其中一个字符串,并在反转的字符串和另一个字符串之间找到最长的公共子字符串(LCS)。因为这听起来像是一个家庭作业或面试问题,剩下的就交给你了 #包括 #包括 使用std::cout; 使用std::endl; 使用std::cin; int main(){ std::字符串字,左(“”); cin>>单词;
有人能帮我一个O(N)解决方案吗?我假设您不能替换或删除任何现有字符 一个好的开始是反转其中一个字符串,并在反转的字符串和另一个字符串之间找到最长的公共子字符串(LCS)。因为这听起来像是一个家庭作业或面试问题,剩下的就交给你了
#包括
#包括
使用std::cout;
使用std::endl;
使用std::cin;
int main(){
std::字符串字,左(“”);
cin>>单词;
大小\u t开始、结束;
for(start=0,end=word.length()-1;start还原字符串
使用modified查找最新的匹配项(最简单的修改是将原始字符串附加到还原的字符串,并忽略len(string)之后的匹配项)
将还原字符串中不匹配的其余部分追加到原始字符串
1和3显然是线性的,2是线性的,因为Knuth-Morris-Pratt是线性的。如果只允许附加
Scala解决方案:
def isPalindrome(s: String) = s.view.reverse == s.view
def makePalindrome(s: String) =
s + s.take((0 to s.length).find(i => isPalindrome(s.substring(i))).get).reverse
如果你被允许在任何地方插入字符
每个回文都可以看作是一组嵌套的字母对
a n n a b o b
| | | | | * |
| -- | | |
--------- -----
若回文长度n为偶数,则有n/2对,如果是奇数,则中间有n/2对和一个字母(称之为退化的对)。
让我们用一对字符串索引来表示它们-左索引从字符串的左端开始计数,右索引从字符串的右端开始计数,两端都以索引0开始
现在,让我们从外部到内部写对。在我们的示例中:
anna: (0, 0) (1, 1)
bob: (0, 0) (1, 1)
为了使任何字符串都成为回文,我们将从字符串的两端一次添加一个字符,并在每一步中最终添加一个字符以生成一对正确的相同字符
例如:
假设输入字是“blob”
对(0,0)是(b,b)好的,没什么可做的,这对很好。让我们增加计数器
对(1,1)是(l,o)。不匹配。所以让我们从左边的位置1添加“o”。现在我们的单词变成了“bolob”
对(2,2)。我们甚至不需要查看字符,因为我们指向字符串中的同一索引。完成
等一下,但我们这里有一个问题:在第2点中,我们任意选择在左侧添加一个字符。但我们也可以在右侧添加一个字符“l”。这将产生“blolb”,也是一个有效的回文。这有关系吗?不幸的是,这有关系,因为前面步骤中的选择可能会影响我们需要修复的对数,从而影响我们在未来步骤中需要添加的字符数
简单算法:搜索所有可能的。这将给我们一个O(2^n)算法。
更好的算法:使用动态规划方法并修剪搜索空间
为了使事情更简单,现在我们将插入新字符与查找正确的嵌套对序列(从外到内)以及稍后修复它们的对齐方式分离。因此对于单词“blob”,我们有以下几种可能性,两者都以退化对结尾:
(0, 0) (1, 2)
(0, 0) (2, 1)
我们找到的这类对越多,修复原始字符串所需添加的字符就越少。找到的每对完整对都会给我们两个可以重用的字符。每对退化对都会给我们一个可以重用的字符
该算法的主循环将以这样的方式迭代计算成对序列,即在步骤1中找到长度为1的所有有效成对序列。下一步将计算长度为2的序列,长度为3的第三个序列等。当在某一步中我们发现不可能时,这意味着上一步包含具有高精度的解最大成对数
在每一步之后,我们将删除帕累托次优序列。如果一个序列的最后一对被另一个序列的最后一对支配,那么它与相同长度的另一个序列相比是次优的。例如,序列(0,0)(1,3)比(0,0)(1,2)差。后者为我们提供了更多的空间来查找嵌套对,并且我们保证至少找到我们为前者找到的所有对。但是序列(0,0)(1,2)既不比(0,0)(2,1)差也不比(0,0)(2,1)好.我们必须注意的一个小细节是,以退化对结尾的序列总是比以完整对结尾的序列更糟糕
在将所有这些结合起来之后:
def makePalindrome(str: String): String = {
/** Finds the pareto-minimum subset of a set of points (here pair of indices).
* Could be done in linear time, without sorting, but O(n log n) is not that bad ;) */
def paretoMin(points: Iterable[(Int, Int)]): List[(Int, Int)] = {
val sorted = points.toSeq.sortBy(identity)
(List.empty[(Int, Int)] /: sorted) { (result, e) =>
if (result.isEmpty || e._2 <= result.head._2)
e :: result
else
result
}
}
/** Find all pairs directly nested within a given pair.
* For performance reasons tries to not include suboptimal pairs (pairs nested in any of the pairs also in the result)
* although it wouldn't break anything as prune takes care of this. */
def pairs(left: Int, right: Int): Iterable[(Int, Int)] = {
val builder = List.newBuilder[(Int, Int)]
var rightMax = str.length
for (i <- left until (str.length - right)) {
rightMax = math.min(str.length - left, rightMax)
val subPairs =
for (j <- right until rightMax if str(i) == str(str.length - j - 1)) yield (i, j)
subPairs.headOption match {
case Some((a, b)) => rightMax = b; builder += ((a, b))
case None =>
}
}
builder.result()
}
/** Builds sequences of size n+1 from sequence of size n */
def extend(path: List[(Int, Int)]): Iterable[List[(Int, Int)]] =
for (p <- pairs(path.head._1 + 1, path.head._2 + 1)) yield p :: path
/** Whether full or degenerated. Full-pairs save us 2 characters, degenerated save us only 1. */
def isFullPair(pair: (Int, Int)) =
pair._1 + pair._2 < str.length - 1
/** Removes pareto-suboptimal sequences */
def prune(sequences: List[List[(Int, Int)]]): List[List[(Int, Int)]] = {
val allowedHeads = paretoMin(sequences.map(_.head)).toSet
val containsFullPair = allowedHeads.exists(isFullPair)
sequences.filter(s => allowedHeads.contains(s.head) && (isFullPair(s.head) || !containsFullPair))
}
/** Dynamic-Programming step */
@tailrec
def search(sequences: List[List[(Int, Int)]]): List[List[(Int, Int)]] = {
val nextStage = prune(sequences.flatMap(extend))
nextStage match {
case List() => sequences
case x => search(nextStage)
}
}
/** Converts a sequence of nested pairs to a palindrome */
def sequenceToString(sequence: List[(Int, Int)]): String = {
val lStr = str
val rStr = str.reverse
val half =
(for (List(start, end) <- sequence.reverse.sliding(2)) yield
lStr.substring(start._1 + 1, end._1) + rStr.substring(start._2 + 1, end._2) + lStr(end._1)).mkString
if (isFullPair(sequence.head))
half + half.reverse
else
half + half.reverse.substring(1)
}
sequenceToString(search(List(List((-1, -1)))).head)
}
def makePalindrome(str:String):String={
/**查找一组点(此处为一对索引)的帕累托最小子集。
*可以在线性时间内完成,无需排序,但O(n logn)并没有那么糟糕;)*/
def paretoMin(点:Iterable[(Int,Int)]):List[(Int,Int)]={
val排序=点到相等排序(标识)
(List.empty[(Int,Int)]/:排序){(result,e)=>
如果(result.isEmpty | | e.| u2这里看到这个解
这比O(N^2)
问题被细分为许多其他子问题
例如:
原“托斯托尔”
反向“rototsot”
这里的第二个位置是“o”,因此通过从原始字符串切入到“t”和“OSOT”,将问题分为两个部分
对于“t”:解决方案为1
对于“OSOT”:解决方案是2,因为LCS是“tot”,需要添加的字符是“os”
所以总数是2+1=3
O(n)时间解。
算法:
需要找到给定字符串中包含最后一个字符的最长回文。然后将不属于回文的所有字符按相反顺序添加到字符串的后面
重点:
在这个问题中,最长的回文
def shortPalin( S):
k=0
lis=len(S)
for i in range(len(S)/2):
if S[i]==S[lis-1-i]:
k=k+1
else :break
S=S[k:lis-k]
lis=len(S)
prev=0
w=len(S)
tot=0
for i in range(len(S)):
if i>=w:
break;
elif S[i]==S[lis-1-i]:
tot=tot+lcs(S[prev:i])
prev=i
w=lis-1-i
tot=tot+lcs(S[prev:i])
return tot
def lcs( S):
if (len(S)==1):
return 1
li=len(S)
X=[0 for x in xrange(len(S)+1)]
Y=[0 for l in xrange(len(S)+1)]
for i in range(len(S)-1,-1,-1):
for j in range(len(S)-1,-1,-1):
if S[i]==S[li-1-j]:
X[j]=1+Y[j+1]
else:
X[j]=max(Y[j],X[j+1])
Y=X
return li-X[0]
print shortPalin("tostotor")
static public void makePalindrome()
{
//string word = "aababaa";
//string word = "abacbaa";
//string word = "abcbd";
//string word = "abacac";
//string word = "aBxyxBxBxyxB";
//string word = "Malayal";
string word = "abccadac";
int j = word.Length - 1;
int mark = j;
bool found = false;
for (int i = 0; i < j; i++)
{
char cI = word[i];
char cJ = word[j];
if (cI == cJ)
{
found = true;
j--;
if(mark > i)
mark = i;
}
else
{
if (found)
{
found = false;
i--;
}
j = word.Length - 1;
mark = j;
}
}
for (int i = mark-1; i >=0; i--)
word += word[i];
Console.Write(word);
}
}
str = 'xcbc' # Any string that you want.
arr1 = str.split('')
arr2 = arr1.reverse
count = 0
while(str != str.reverse)
count += 1
arr1.insert(count-1, arr2[count-1])
str = arr1.join('')
end
puts str
puts str.length - arr2.count
#include <iostream>
using namespace std;
int length( char str[])
{ int l=0;
for( int i=0; str[i]!='\0'; i++, l++);
return l;
}
int palin(char str[],int len)
{ static int cnt;
int s=0;
int e=len-1;
while(s<e){
if(str[s]!=str[e]) {
cnt++;
return palin(str+1,len-1);}
else{
s++;
e--;
}
}
return cnt;
}
int main() {
char str[100];
cin.getline(str,100);
int len = length(str);
cout<<palin(str,len);
}
public static void main(String[] args) {
String givenStr = "abtb";
String palindromeStr = covertToPalindrome(givenStr);
System.out.println(palindromeStr);
}
private static String covertToPalindrome(String str) {
char[] strArray = str.toCharArray();
int low = 0;
int high = strArray.length - 1;
int subStrIndex = -1;
while (low < high) {
if (strArray[low] == strArray[high]) {
high--;
} else {
high = strArray.length - 1;
subStrIndex = low;
}
low++;
}
return str + (new StringBuilder(str.substring(0, subStrIndex+1))).reverse().toString();
}
public static void main(String args[])
{
String s=input();
System.out.println(min_operations(s));
}
static String min_operations(String str)
{
int i=0;
int j=str.length()-1;
String ans="";
while(i<j)
{
if(str.charAt(i)!=str.charAt(j))
{
ans=ans+str.charAt(i);
}
if(str.charAt(i)==str.charAt(j))
{
j--;
}
i++;
}
StringBuffer sd=new StringBuffer(ans);
sd.reverse();
return (sd.toString());
}