📜  最小回文子数组删除以使数组为空(1)

📅  最后修改于: 2023-12-03 15:40:16.301000             🧑  作者: Mango

最小回文子数组删除以使数组为空

介绍

本题目要求删除数组中的最小回文子数组,使得数组为空。

回文子数组是指从数组中取出一段连续的元素,将这些元素反转后与原有的序列完全一致。

例如,对于数组 [1, 2, 3, 2, 1],它的最小回文子数组是 [2, 3, 2],如果将其删除后,剩余的数组为 [1, 1],不再是回文数组。若将 [1, 2, 3] 删除,得到的新数组 [2, 1] 依然是回文数组。

解法

我们可以通过将整个数组视为字符串,使用动态规划的方法来解决这个问题。

具体来说,我们可以首先枚举回文数组的长度 $len$,由于对于任意回文数组 $s$,其长度 $|s|$ 为奇数或偶数,因此我们分别考虑这两种情况:

  • 当 $|s|$ 为奇数时,我们枚举回文数组的中心 $mid$,那么该回文数组就是 $s[mid - k], s[mid - k + 1], \cdots, s[mid + k]$($k = \lfloor\frac{len}{2}\rfloor$)。
  • 当 $|s|$ 为偶数时,我们枚举回文数组的中心位置为 $mid$ 和 $mid + 1$,那么该回文数组就是 $s[mid - k], s[mid - k + 1], \cdots, s[mid + k + 1]$($k = \lfloor\frac{len}{2}\rfloor - 1$)。

在枚举出回文数组后,我们可以用双指针分别从左右两端不断向中间移动,判断是否为回文数组。

对于任意 $i \in [0, n - 1]$,我们定义 $f(i)$ 表示将 $s[0 \cdots i]$ 删去最小回文子数组后得到的最少步数,则我们最终要求的答案即为 $f(n - 1)$。

初始化时,根据定义有 $f(0) = 1$,因为当 $n = 1$ 时,本身就是回文数组,需要删去才能变为空数组。

对于 $i > 0$,我们考虑 $f(i)$ 的计算方式:

  • 如果 $s[0 \cdots i]$ 本身就是回文数组,则 $f(i) = 1$。
  • 否则,我们枚举所有的最小回文子数组 $s[l \cdots r]$,使得 $i \in [l, r]$,并状态转移:

$$f(i) = \min\limits_{l \leq j \leq r}f(j - 1) + r - j + 1$$

其中,在上述枚举过程中,我们可以预处理出所有的 $s[i \cdots j]$ 是否为回文数组。

最终,我们得到的 $f(n - 1)$ 就是将最小回文子数组删去后得到的最少步数。

代码

下面是 Python3 代码实现:

class Solution:
    def minimumMoves(self, arr: List[int]) -> int:        
        n = len(arr)
        is_palindrome = [[False] * n for _ in range(n)]
        for i in range(n):
            is_palindrome[i][i] = True

        for len_ in range(2, n + 1):
            for i in range(n - len_ + 1):
                j = i + len_ - 1
                if len_ == 2:
                    is_palindrome[i][j] = (arr[i] == arr[j])
                else:
                    is_palindrome[i][j] = (arr[i] == arr[j] and is_palindrome[i + 1][j - 1])

        f = [1] * n
        for i in range(1, n):
            if is_palindrome[0][i]:
                f[i] = 1
                continue
            for j in range(i):
                if is_palindrome[j + 1][i]:
                    f[i] = min(f[i], f[j] + 1)

        return f[n - 1]