关于问题how to convert a string to palindrome with minimum number of removals of characters of the string?。我编写程序来测试接受的答案。但递归需要太多时间。如何解决或改善这个问题?以下是接受的答案:
设dp [i,j] =将子串[i,j]转换为回文所需的最小删除次数。我们有:
dp[i, i] = 0 for all i (every single character is a palindrome)
至 找到dp [i,j],让我们考虑一个随机字符串。我们有两个 可能性:
第一个和最后一个字符相等:a [i] == a [j]。在这种情况下, 我们可以将问题减少到找到最小数量的字符 需要删除才能使子串[i + 1,j-1]成为a 回文。
- 醇>
第一个和最后一个字符不相等:a [i]!= a [j]。 在这种情况下,我们需要删除其中一个。我们将删除那个 引导我们找到更好的解决方案。
/* remvoe the least characters to make a string be palindrome */
#include <stdio.h>
#include <string.h>
#define MAXLINE 4096
int func(char *p, int low, int high);
int min(int m, int n); // get the minimal value
int main(void)
{
char str[MAXLINE];
int ret;
while (scanf("%s", str) != EOF) { // input in a loop
ret = func(str, 0, strlen(str) - 1); // call func
printf("%d\n", ret);
}
return 0;
}
/* find the minimal number of characters in a string,
* which are needed removed to make the string be palindrome
*/
int func(char *p, int low, int high)
{
int n;
int l;
int r;
if (low >= high) {
return 0;
}
if (p[low] == p[high]) { // needn't remove
n = func(p, low + 1, high - 1);
}
else {
l = func(p, low + 1, high);
r = func(p, low, high - 1);
n = min(l, r) + 1;
}
return n;
}
/* return the minimal variable */
int min(int m, int n)
{
return (m < n ? m : n);
}
答案 0 :(得分:1)
一个关键的改进是认识到当只消除字符串的一边时,另一边必须匹配(另一边有一个字符,即使它本身也是如此),否则为什么不消除双方?
当移除一侧的角色时,从另一侧向另一侧寻找另一侧的角色。 (总是找到匹配。)这消除了许多不必要的递归路径。
二次改进“短路”如下。无需测试其他组合,因为它们无法改善结果。
if (left == 1) return 1;
int func(const char *p, int low, int high) {
int n;
int left;
int right;
count++;
if (low >= high) {
return 0;
}
if (p[low] == p[high]) { // needn't remove
n = func(p, low + 1, high - 1);
} else {
#if 0
left = func(p, low + 1, high);
// if (left == 0) return 1;
right = func(p, low, high - 1);
n = min(left, right) + 1;
#else
int delta;
// remove low, keep high as part of palindrome
delta = 1;
while (p[low + delta] != p[high])
delta++;
left = func(p, low + delta, high) + delta;
if (left == 1) return 1;
// remove high, keep low as part of palindrome
delta = 1;
while (p[low] != p[high - delta])
delta++;
right = func(p, low, high - delta) + delta;
if (right <= 2) return right;
n = min(left, right);
// remove first and last
//int both = func(p, low + 1, high-1) + 1 + (high > (low + 1));
int both = func(p, low + 1, high - 1) + 2;
n = min(n, both);
#endif
}
return n;
}
鼠标悬停以获得OP's test string的最终结果(隐藏,以防OP不想立即看到它。)
计数= 13090 RET = 45 STR = 'jfdasflkjddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddfjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj'
小改进使用const
。知道缓冲区不变,一些编译器将生成更有效的代码。更好的编译器可能会检测到这一点。
// int func(char *p, int low, int high)
int func(const char *p, int low, int high)
一些测试驱动程序代码
#include <stdio.h>
#include <string.h>
#define MAXLINE 4096
unsigned long long count = 0;
int func(const char *p, int low, int high);
int min(int m, int n); // get the minimal value
void testfunc(const char *str) {
count = 0;
int ret = func(str, 0, (int) strlen(str) - 1); // call func
printf(" count = %llu", count);
printf(" ret = %d", ret);
printf(" str = '%s' ++", str);
puts("");
fflush(stdout);
}
int main(void) {
char str[MAXLINE];
int ret;
char t[] =
"jfdasflkjdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
"ddddddddddddddfjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj";
for (size_t i = 0; t[i]; i++) {
strncpy(str, t, i);
str[i] = 0;
testfunc(str);
}
return 0;
}
int min(int m, int n) {
return (m < n ? m : n);
}
int func(const char *p, int low, int high) {
...
答案 1 :(得分:0)
你不应该递归地调用它,因为这导致多次执行相同的检查(一些范围将被多次检查,而实际上只需要一次检查)。相反,你应该使用&#34;动态编程&#34;方法,从下到上构建。这意味着你需要创建一个二维数组windows_package
,它存储范围dp[i][j], i<j
到i
的最大回文长度。因此,如果j
首先进行j=i+k
的构建,那么k=0
等等。