最近我在https://leetcode.com/problems/palindrome-partitioning-ii/上遇到了这个问题:
给出一个字符串s
,分区s
,这样分区的每个子字符串都是回文。
返回s
的回文分区所需的最小切割数。
Example:
Input: "aab"
Output: 1
Explanation: The palindrome partitioning ["aa","b"] could be produced using 1 cut.
这是我在互联网上发现的C解决方案。我一直在尝试了解DP阵列正在跟踪什么,并且我发现在dp[j]
处,将回文分区的数量存储在字符串的第j
个字符中。因此,dp[1]
存储一个字母元素所需的分区数,该分区数将始终为0,{str1的前两个字母则为dp[2]
。
我不明白的是,为什么我们要初始化dp[0] = -1
?这似乎有些不直观,我无法弄清楚发生这种情况的原因。
int _min(int a, int b) {
return a < b ? a : b;
}
int minCut(char* s) {
int *dp, n, i, k;
n = strlen(s);
dp = malloc((n + 1) * sizeof(int)); // number of cuts on length
//assert(dp);
dp[0] = -1;
for (i = 0; i < n; i ++) {
dp[i + 1] = dp[i] + 1;
}
for (i = 0; i < n; i ++) {
dp[i + 1] = _min(dp[i + 1], dp[i] + 1);
for (k = 1; // "aba"
i - k >= 0 &&
i + k < n &&
s[i - k] == s[i + k];
k ++) {
dp[i + k + 1] = _min(dp[i + k + 1], dp[i - k] + 1);
}
for (k = 1; // "aaaa"
i - k + 1 >= 0 &&
i + k < n &&
s[i - k + 1] == s[i + k];
k ++) {
dp[i + k + 1] = _min(dp[i + k + 1], dp[i - k + 1] + 1);
}
}
i = dp[n];
free(dp);
return i;
}
我已经使用此函数进行了一些跟踪,但似乎仍然找不到答案:这是我尝试过minCut(“ aba”)的地方,在第二次每次迭代的开始都打印i和dp包装为循环,k
也出现在第一个嵌套的循环中。
i = 0
dp = [-1, 0, 1, 2]
i = 1
dp = [-1, 0, 1, 2]
k = 1
i = 2
dp = [-1, 0, 1, 0]
当涉及元素'b'
时,通过向前和向后扩展,我们发现"aba"
是回文。然后,有了这个:dp[i + k + 1] = _min(dp[i + k + 1], dp[i - k] + 1);
,我们得到了dp[3] = _min(dp[3], dp[1 - 1] + 1) = _min(2, -1 + 1) = 0
。
令人困惑的是,为什么基本情况为dp[0] = -1
,以及它如何影响_min(dp[3], dp[0] + 1)
。基本上,我们要回到没有检测到回文的地方,并取那个值+1。但是为什么minCut("") = -1
呢?
我已经尝试了2.5个小时,但是我仍然无法弄清。
答案 0 :(得分:1)
这是一个保护值。当我们不想写额外的if
时使用这些东西,然后在数据中添加一些 guard 元素,例如代替n*n
矩阵,我们可以使用(n+2)*(n+2)
矩阵,在守卫位置使用一些方便的值,通常为零。
观察到发现的每一个下一个回文,您需要再进行一次切割。 + 1
是在更新dp
的同时实现的。但是,当您发现第一回文时,您无需为此做任何准备。这与杆切割相同,将杆切割成一件,根本不需要切割。
顺便说一句,如果s
的长度为零,则程序返回-1
,这是错误的。
BTW2,如果输入字符串看起来像aaa...aaa
,则此程序将花费大量时间。基本上是O(n^2)
。