给出一个字符串S.我们需要告诉我们是否可以通过从中删除一个字母来使其成为回文。 我有一个O(N ^ 2)方法,通过修改编辑距离方法。他们有更好的方法吗?
我的方法:
int ModifiedEditDistance(const string& a, const string& b, int k) {
int i, j, n = a.size();
int dp[MAX][MAX];
memset(dp, 0x3f, sizeof dp);
for (i = 0 ; i < n; i++)
dp[i][0] = dp[0][i] = i;
for (i = 1; i <= n; i++) {
int from = max(1, i-k), to = min(i+k, n);
for (j = from; j <= to; j++) {
if (a[i-1] == b[j-1]) // same character
dp[i][j] = dp[i-1][j-1];
// note that we don't allow letter substitutions
dp[i][j] = min(dp[i][j], 1 + dp[i][j-1]); // delete character j
dp[i][j] = min(dp[i][j], 1 + dp[i-1][j]); // insert character i
}
}
return dp[n][n];
}
如何提高空间复杂度,因为字符串的最大大小可以达到10 ^ 5.
请帮忙。
示例:让String为abc然后回答是&#34; NO&#34;如果字符串是&#34; abbcbba,那么答案是&#34;是&#34;
答案 0 :(得分:9)
关键的观察是,如果第一个和最后一个字符是相同的,那么你不需要删除其中任何一个;也就是说xSTRINGx
可以通过删除单个字母变成回文,当且仅当STRING
可以(只要STRING
至少有一个字符长)。
你想定义一个方法(借口Java语法 - 我不是C ++编码器):
boolean canMakePalindrome(String s, int startIndex, int endIndex, int toRemove);
通过删除startIndex
字符来确定从endIndex-1
到toRemove
的字符串部分是否可以成为回文结构。
当您考虑canMakePalindrome(s, i, j, r)
时,您可以根据较小的问题来定义它:
j-i
为1,则返回true;如果它为0则返回true当且且仅当r
为0.这里的要点是1个字符的字符串是回文,无论你是否删除了一个字符;一个0长度的字符串是一个回文,但不能通过删除一个字符组成一个(因为没有任何要删除)。s[i]
和s[j-1]
相同,则答案与canMakePalindrome(s, i+1, j-1, r)
相同。s[i]
或s[j-1]
需要删除。如果toRemove
为零,则返回false,因为您还没有要删除任何字符。如果toRemove
为1,则如果canMakePalindrome(s, i+1, j, 0)
或canMakePalindrome(s, i, j-1, 0)
,则返回true。这是因为如果你删除这两个字符中的一个,你现在正在测试它是否已经是一个回文。现在,我认为这很容易编码。
如果您想允许删除多个字符,您可以使用相同的想法,但使用动态编程。只需移除一个字符,动态编程将减少常数因子,但不会降低渐近时间复杂度(字符串长度的线性)。
答案 1 :(得分:4)
Psudocode(像这样的东西我根本没有测试过它。)
它基于检测您可以移除角色的条件,即
O(n)及时,O(1)在空间。
bool foo(const std::string& s)
{
int i = 0;
int j = s.size()-1;
int mismatch_count = 0;
while (i < j)
{
if (s[i]==s[j])
{
i++; j--;
}
else
{
mismatch_count++;
if (mismatch_count > 1) break;
//override first preference if cannot find match for next character
if (s[i+1] == s[j] && ((i+2 >= j-1)||s[i+2]==s[j-1]))
{
i++;
}
else if (s[j-1]==s[i])
{
j--;
}
else
{
mismatch_count++; break;
}
}
}
//can only be a palendrome if you remove a character if there is exactly one mismatch
//or if a palendrome
return (mismatch_count == 1) || (mismatch_count == 0);
}
答案 2 :(得分:2)
这是一个(稍微不完整)的解决方案,需要O(n)时间和O(1)空间。
// returns index to remove to make a palindrome; string::npos if not possible
size_t willYouBeMyPal(const string& str)
{
size_t toRemove = string::npos;
size_t len = str.length();
for (size_t c1 = 0, c2 = len - 1; c1 < c2; ++c1, --c2) {
if (str[c1] != str[c2]) {
if (toRemove != string::npos) {
return string::npos;
}
bool canRemove1 = str[c1 + 1] == str[c2];
bool canRemove2 = str[c1] == str[c2 - 1];
if (canRemove1 && canRemove2) {
abort(); // TODO: handle the case where both conditions are true
} else if (canRemove1) {
toRemove = c1++;
} else if (canRemove2) {
toRemove = c2--;
} else {
return string::npos;
}
}
}
// if str is a palindrome already, remove the middle char and it still is
if (toRemove == string::npos) {
toRemove = len / 2;
}
return toRemove;
}
如果你得到这个,练习就是做什么:
abxyxcxyba
正确的解决方案是:
ab_yxcxyba
但是你可能会走上一条糟糕的道路:
abxyxcx_ba
所以当你找到&#34; next&#34;双方的角色是一个可能的解决方案,你需要评估两种可能性。
答案 3 :(得分:2)
我写了一个O(n)复杂度的样本,适用于我投入的测试。虽然不多:D 它背后的想法是忽略它们相同的第一个和最后一个字母,如果它们不相同则删除它们中的一个,并推断当字符串足够小时会发生什么。相同的结果可以使用循环而不是递归进行存档,这将节省一些空间(使其成为O(1)),但它更难以理解并且更容易出错IMO。
bool palindrome_by_1(const string& word, int start, int end, bool removed = false) // Start includes, end excludes
{
if (end - start == 2){
if (!removed)
return true;
return word[start] == word[end - 1];
}
if (end - start == 1)
return true;
if (word[start] == word[end - 1])
return palindrome_by_1(word, start + 1, end - 1, removed);
// After this point we need to remove a letter
if (removed)
return false;
// When two letters don't match, try to eliminate one of them
return palindrome_by_1(word, start + 1, end, true) || palindrome_by_1(word, start, end - 1, true);
}
答案 4 :(得分:1)
检查单个字符串是否是回文结构是O(n)。你可以实现一个类似的算法,而不是移动两个指针,一个从开始,另一个从结束。只要字符相同,移动每个指针,并在第一个不匹配时尝试匹配您可以跳过的字符,并且只要其余字符相同,就继续移动两个指针。跟踪第一个不匹配。这是O(n)。
答案 5 :(得分:1)
我希望我的算法在没有提供代码的情况下通过。
如果一个单词a 1 a 2 .... a n 可以通过删除 k <做成回文/ sub>,我们可以搜索k如下:
如果 1 != a n ,那么唯一可能的k将是1或n。只需检查 1 a 2 .... a n-1 或 2 a 3 .... a n 是回文。
如果 1 == a n ,下一步就是为 2 .... a 解决同样的问题n-1个子>。所以我们在这里有一个递归。
答案 6 :(得分:0)
public static boolean pal(String s,int start,int end){
if(end-start==1||end==start)
return true;
if(s.charAt(start)==s.charAt(end))
return pal(s.substring(start+1, end),0,end-2);
else{
StringBuilder sb=new StringBuilder(s);
sb.deleteCharAt(start);
String x=new String(sb);
if(x.equals(sb.reverse().toString()))
return true;
StringBuilder sb2=new StringBuilder(s);
sb2.deleteCharAt(end);
String x2=new String(sb2);
if(x2.equals(sb2.reverse().toString()))
return true;
}
return false;
}
答案 7 :(得分:0)
我尝试了以下内容,f和b是字符不匹配的索引
int canwemakepal(char *str)//str input string
{
long int f,b,len,i,j;
int retval=0;
len=strlen(str);
f=0;b=len-1;
while(str[f]==str[b] && f<b)//continue matching till we dont get a mismatch
{
f++;b--;
}
if(f>=b)//if the index variable cross over each other, str is palindrome,answer is yes
{
retval=1;//true
}
else if(str[f+1]==str[b])//we get a mismatch,so check if removing character at str[f] will give us a palindrome
{
i=f+2;j=b-1;
while(str[i]==str[j] && i<j)
{
i++;j--;
}
if(i>=j)
retval=1;
else
retval=0;
}
else if(str[f]==str[b-1])//else check the same for str[b]
{
i=f+1;j=b-2;
while(str[i]==str[j] && i<j)
{
i++;j--;
}
if(i>=j)
retval=1;
else
retval=0;
}
else
retval=0;
return retval;
}
答案 8 :(得分:0)
I created this solution,i tried with various input giving correct result,still not accepted as correct solution,Check it n let me know if m doing anything wrong!! Thanks in advance.
public static void main(String[] args)
{
Scanner s = new Scanner(System.in);
int t = s.nextInt();
String result[] = new String[t];
short i = 0;
while(i < t)
{
String str1 = s.next();
int length = str1.length();
String str2 = reverseString(str1);
if(str1.equals(str2))
{
result[i] = "Yes";
}
else
{
if(length == 2)
{
result[i] = "Yes";
}
else
{
int x = 0,y = length-1;
int counter = 0;
while(x<y)
{
if(str1.charAt(x) == str1.charAt(y))
{
x++;
y--;
}
else
{
counter ++;
if(str1.charAt(x) == str1.charAt(y-1))
{
y--;
}
else if(str1.charAt(x+1) == str1.charAt(y))
{
x++;
}
else
{
counter ++;
break;
}
}
}
if(counter >= 2)
{
result[i] = "No";
}
else
result[i]="Yes";
}
}
i++;
} // Loop over
for(int j=0; j<i;j++)
{
System.out.println(result[j]);
}
}
public static String reverseString(String original)
{
int length = original.length();
String reverse = "";
for ( int i = length - 1 ; i >= 0 ; i-- )
reverse = reverse + original.charAt(i);
return reverse;
}