回文分区问题中该DP阵列的基本情况dp [0] = -1的目的是什么?

时间:2019-08-16 05:07:27

标签: c arrays algorithm dynamic-programming

最近我在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个小时,但是我仍然无法弄清。

1 个答案:

答案 0 :(得分:1)

这是一个保护值。当我们不想写额外的if时使用这些东西,然后在数据中添加一些 guard 元素,例如代替n*n矩阵,我们可以使用(n+2)*(n+2)矩阵,在守卫位置使用一些方便的值,通常为零。

观察到发现的每一个下一个回文,您需要再进行一次切割。 + 1是在更新dp的同时实现的。但是,当您发现第一回文时,您无需为此做任何准备。这与杆切割相同,将杆切割成一件,根本不需要切割。

顺便说一句,如果s的长度为零,则程序返回-1,这是错误的。

BTW2,如果输入字符串看起来像aaa...aaa,则此程序将花费大量时间。基本上是O(n^2)