452.最小移动次数使数组相等 | 豆包MarsCode AI 刷题

32 阅读3分钟

问题描述

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

  1. 反转数组 A,即使数组 A 的元素顺序完全颠倒。
  2. 在 [1, N] 范围内选择一个整数 i,然后可以对 A[i] 添加或减去任意值。

你的任务是帮助小C找到使数组 A 等于数组 B 所需的最小操作次数。

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

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

问题理解

我们需要将数组 A 转换为数组 B,允许的操作有两种:

  1. 反转数组 A
  2. 对数组 A 中的任意元素进行加减操作。

目标是找到最小的操作次数,使得数组 A 变为数组 B

算法步骤

  1. 初始化:定义一个函数 solution,接收参数 NA 和 B

  2. 直接比较

    • 遍历数组 A 和数组 B,逐个元素比较。
    • 如果 A[i] 不等于 B[i],则需要进行一次调整操作。
    • 统计需要调整的元素个数,记为 count_no_reverse
  3. 反转比较

    • 反转数组 A,得到新的数组 A_reversed
    • 遍历数组 A_reversed 和数组 B,逐个元素比较。
    • 如果 A_reversed[i] 不等于 B[i],则需要进行一次调整操作。
    • 统计需要调整的元素个数,并加上一次反转操作的次数(1次),记为 count_reverse
  4. 比较结果

    • 比较 count_no_reverse 和 count_reverse
    • 选择操作次数较小的那个作为最终结果。

代码实现

def solution(N: int, A: list, B: list) -> int:
    count_no_reverse = 0
    for i in range(N):
        if A[i] != B[i]:
            count_no_reverse += 1

    count_reverse = 1  # 反转操作本身算一次操作
    A_reversed = A[::-1]
    for i in range(N):
        if A_reversed[i] != B[i]:
            count_reverse += 1

    return min(count_no_reverse, count_reverse)

关键步骤注释

  • 直接比较:在 count_no_reverse 中,我们直接遍历数组 A 和数组 B,计算需要调整的元素个数。
  • 反转比较:在 count_reverse 中,我们先反转数组 A,然后再次遍历数组 A 和数组 B,计算需要调整的元素个数。
  • 比较结果:通过 min(count_no_reverse, count_reverse) 返回两种情况中操作次数较小的那个。

时间复杂度

  1. 直接比较

    • 遍历数组 A 和数组 B,逐个元素比较。
    • 这一步的时间复杂度是 O(N),其中 N 是数组的长度。
  2. 反转比较

    • 反转数组 A,得到新的数组 A_reversed
    • 反转操作的时间复杂度是 O(N)
    • 遍历数组 A_reversed 和数组 B,逐个元素比较。
    • 这一步的时间复杂度也是 O(N)
  3. 比较结果

    • 比较 count_no_reverse 和 count_reverse
    • 这一步的时间复杂度是 O(1)

综合以上步骤,总的时间复杂度是 O(N)

空间复杂度

  1. 直接比较

    • 只需要常数空间来存储 count_no_reverse
    • 空间复杂度是 O(1)
  2. 反转比较

    • 需要额外的空间来存储反转后的数组 A_reversed
    • 这一步的空间复杂度是 O(N)
  3. 比较结果

    • 只需要常数空间来存储 count_reverse
    • 空间复杂度是 O(1)

综合以上步骤,总的空间复杂度是 O(N)

总结

  • 时间复杂度O(N)
  • 空间复杂度O(N)