最小移动次数使数组相等题目解析 | 豆包MarsCode AI刷题

38 阅读4分钟

问题描述

小C有两个长度为 N 的数组 A 和 B。他可以进行以下两种操作,来将数组 A 转换为数组 B:

反转数组 A,即使数组 A 的元素顺序完全颠倒。 在 [1, N] 范围内选择一个整数 i,然后可以对 A[i] 添加或减去任意值。 你的任务是帮助小C找到使数组 A 等于数组 B 所需的最小操作次数。

例如:当 N = 3,A = [1, 2, 5],B = [4, 2, 1] 时,最佳操作如下:

第一步反转数组 A,得到新数组 A = [5, 2, 1]。 第二步从位置 1 减去 1,得到新数组 A = [4, 2, 1]。 因此,答案是 2。

测试样例

样例1:

输入:N = 3,A = [1, 2, 5],B = [4, 2, 1] 输出:2

样例2:

输入:N = 4,A = [7, 8, 6, 2],B = [6, 2, 8, 7] 输出:3

样例3:

输入:N = 2,A = [3, 9],B = [9, 3] 输出:1

代码提示

理解问题:

你需要计算将数组 A 转换为数组 B 所需的最小操作次数。 操作包括反转数组 A 和调整数组 A 中的元素。

数据结构选择:

使用列表来存储数组 A 和 B。

算法步骤:

计算不反转数组 A 时的调整次数。 反转数组 A,然后计算调整次数。 比较两种情况下的调整次数,选择最小值。

代码实现:

使用 count_adjustments 函数来计算调整次数。 反转数组 A 后,再次调用 count_adjustments 函数。 返回两种情况下的最小调整次数。

代码框架

def solution(N: int, A: list, B: list) -> int:
    # 计算调整次数的辅助函数
    def count_adjustments(A, B):
        adjustments = 0
        for i in range(N):
            if A[i] != B[i]:
                adjustments += 1
        return adjustments

    # 计算不反转的情况下的调整次数
    adjustments_normal = count_adjustments(A, B)

    # 反转数组 A
    A_reversed = A[::-1]

    # 计算反转后的调整次数
    adjustments_reversed = count_adjustments(A_reversed, B)

    # 返回最小的调整次数
    return min(adjustments_normal, adjustments_reversed + 1)

if __name__ == '__main__':
    print(solution(N = 3, A = [1, 2, 5], B = [4, 2, 1]) == 2)
    print(solution(N = 4, A = [7, 8, 6, 2], B = [6, 2, 8, 7]) == 3)
    print(solution(N = 2, A = [3, 9], B = [9, 3]) == 1)

关键步骤注释

count_adjustments 函数用于计算数组 A 和 B 之间的调整次数。

A_reversed = A[::-1] 用于反转数组 A。

min(adjustments_normal, adjustments_reversed + 1) 用于返回最小的调整次数,其中 adjustments_reversed + 1 是因为反转操作本身也算一次操作。

可能面对的问题:如何优化这个算法以减少时间复杂度?

优化思路

减少重复计算:

当前代码中,count_adjustments 函数被调用了两次,一次是计算不反转的情况,一次是计算反转后的情况。我们可以通过一次遍历同时计算这两种情况,从而减少重复计算。

避免不必要的反转:

反转数组 A 的操作本身是 O(N) 的时间复杂度。如果我们在一次遍历中同时计算反转和不反转的情况,就可以避免这个额外的反转操作。

优化后的算法步骤

一次遍历计算两种情况:

在一次遍历中,同时计算不反转和反转情况下的调整次数。 使用两个变量分别记录不反转和反转情况下的调整次数。

返回最小调整次数:

最后返回两种情况下的最小调整次数。

代码实现

def solution(N: int, A: list, B: list) -> int:
    # 初始化调整次数
    adjustments_normal = 0
    adjustments_reversed = 0

    # 一次遍历同时计算不反转和反转情况下的调整次数
    for i in range(N):
        if A[i] != B[i]:
            adjustments_normal += 1
        if A[i] != B[N - 1 - i]:
            adjustments_reversed += 1

    # 返回最小的调整次数
    return min(adjustments_normal, adjustments_reversed + 1)

if __name__ == '__main__':
    print(solution(N = 3, A = [1, 2, 5], B = [4, 2, 1]) == 2)
    print(solution(N = 4, A = [7, 8, 6, 2], B = [6, 2, 8, 7]) == 3)
    print(solution(N = 2, A = [3, 9], B = [9, 3]) == 1)

关键步骤注释

adjustments_normal 用于记录不反转情况下的调整次数。

adjustments_reversed 用于记录反转情况下的调整次数。

if A[i] != B[N - 1 - i] 用于检查反转后的元素是否匹配。

min(adjustments_normal, adjustments_reversed + 1) 用于返回最小的调整次数,其中 adjustments_reversed + 1 是因为反转操作本身也算一次操作。

时间复杂度分析

优化后的算法只需要一次遍历数组 A 和 B,时间复杂度为 O(N),相比原来的 O(2N) 有所减少。

总结

本题考查了数据结构和算法优化,难度适中。