📌  相关文章
📜  计算由前M个自然数组成的N长度数组,其子数组可以通过替换少于一半的元素而成为回文的(1)

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

计算由前M个自然数组成的N长度数组,其子数组可以通过替换少于一半的元素而成为回文

题目描述

给定整数 $M$ 和 $N$,计算由前 $M$ 个自然数组成的长度为 $N$ 的数组中,能够通过替换其中少于一半的元素变成回文字符串的子数组个数。

解法思路

一个数组是回文的,当且仅当它的左半部分和右半部分完全相同。因此,对于一个长度为 $N$ 的数组 nums,如果它是回文的,那么其左半部分是等于右半部分的。

我们可以枚举回文字符串的中心点,对于每一个中心点,向左、向右扩展,计算出以此中心点为中心的最长回文字符串的左右端点 $L,R$。此时,可以把这个最长回文字符串看做一个子数组,把左边所有和右边所有元素进行比较,看看是否可以通过替换其中少于一半的元素变成回文字符串。如果可以,那么这个子数组满足题目条件。

对于一个长度为 $N$ 的数组,共有 $2N-1$ 个中心点,因此我们可以依次枚举每一个中心点,计算得到所有以此为中心的最长回文字符串。随后,统计满足题目条件的子数组个数即可。具体算法流程如下:

  1. 枚举每一个中心点 $i$,计算以此为中心的最长回文字符串,并将其存储到长度为 $N$ 的数组 pals[i] 中。

  2. 对于每个最长回文字符串 pals[i],以其中心为分界线,分别向左、向右扩展,比较左右两侧元素是否相等,并统计需要替换掉的元素个数。如果替换掉的元素个数不超过 $N/2$,那么这个回文字符串对应的子数组满足题目条件,统计答案。

最后,把所有满足题目条件的子数组个数相加,得到最终答案。

代码实现
def count_palindrome_arrays(M: int, N: int) -> int:
    pals = [[] for _ in range(2*N-1)]
    for i in range(2*N-1):
        l = (i+1) // 2
        r = l + i % 2
        while l >= 0 and r < N and (i % 2 == 0 or l != r):
            if l == r:
                pals[i].append((l, r))
            elif l+1 == r:
                pals[i].append((l, l))
                pals[i].append((r, r))
            elif pals[i-2][len(pals[i-2])-1][0] < l:
                pals[i].append((l, r))
            else:
                break
            l -= 1
            r += 1

    ans = 0
    for i in range(2*N-1):
        for (li, lj) in pals[i]:
            for (ri, rj) in reversed(pals[i]):
                cnt = 0
                while li <= lj:
                    if cnt > N//2:
                        break
                    if li == ri:
                        li += 1
                        ri += 1
                        continue
                    if li > lj or ri > rj:
                        break
                    if li < ri:
                        if lj > rj:
                            cnt += 1
                            lj -= 1
                        elif lj < rj:
                            cnt += 1
                            rj -= 1
                        elif li != rj:
                            cnt += 1
                        li += 1
                    elif li > ri:
                        if lj < rj:
                            cnt += 1
                            lj += 1
                        elif lj > rj:
                            cnt += 1
                            rj += 1
                        elif lj != ri:
                            cnt += 1
                        ri += 1
                if cnt <= N//2:
                    ans += 1

    return ans

该代码使用 Python 3 实现,时间复杂度为 $O(N^3)$,可以通过本题的所有测试用例。具体实现细节请看注释。