最小操作次数转换数组 | 豆包MarsCode AI刷题

123 阅读4分钟

题目描述

给定两个长度为 N 的整数数组 A 和 B,要求找到最小的操作次数,使得数组 A 可以变成数组 B。可以进行以下两种操作:

  1. 反转数组 A:即将数组 A 的顺序完全颠倒。
  2. 修改单个元素:选择数组 A 中某个位置的元素,对其添加或减去任意值。

任务是计算最小的操作次数,其中每次操作计为 1 次。下面通过一个具体的例子来理解题目:

示例 1:

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

  • 输出:2

    • 操作 1:反转数组 A,得到 [5, 2, 1]。
    • 操作 2:对 A[0] 减去 1,得到 [4, 2, 1]。

答案是 2,因为我们用了 2 次操作。

思路解析

我们需要思考如何将数组 A 转换为数组 B。最明显的思路是可以分两步:

  1. 直接操作 A 到 B:不进行反转,直接修改 A 中每个元素使其变为 B 中的对应元素。
  2. 反转操作:先将数组 A 反转,再通过修改操作将反转后的数组转换为数组 B。

通过比较这两种方法的操作次数,我们就可以找到最小的操作次数。

操作的具体计算

为了计算操作次数,我们需要定义一个辅助函数来计算数组 A 和 B 中对应位置的不同元素个数。因为每次操作只能修改一个元素,因此两个数组中不同的元素个数就是我们所需的修改次数。

另外,反转数组的操作也需要考虑其对操作次数的影响。反转后的数组可能需要较少的修改操作,因此需要在两种方式下选择最少的操作次数。

代码实现

import java.util.Arrays;

public class Main {
    // 计算将数组 A 转换为 B 的最小操作次数
    public static int solution(int N, int[] A, int[] B) {
        // 计算不反转的情况下的最小操作次数
        int directChange = countChanges(A, B);

        // 创建一个反转后的数组 A'
        int[] reversedA = new int[N];
        for (int i = 0; i < N; i++) {
            reversedA[i] = A[N - 1 - i];
        }

        // 计算反转后的情况下的最小操作次数
        int reversedChange = countChanges(reversedA, B);

        // 返回两种情况中的最小值
        return Math.min(directChange, reversedChange + 1); // 反转操作计一次
    }

    // 计算两个数组中不相同的位置个数
    private static int countChanges(int[] A, int[] B) {
        int changes = 0;
        for (int i = 0; i < A.length; i++) {
            if (A[i] != B[i]) {
                changes++;
            }
        }
        return changes;
    }

    public static void main(String[] args) {
        // 测试用例
        System.out.println(solution(3, new int[] { 1, 2, 5 }, new int[] { 4, 2, 1 }) == 2);
        System.out.println(solution(4, new int[] { 7, 8, 6, 2 }, new int[] { 6, 2, 8, 7 }) == 3);
        System.out.println(solution(2, new int[] { 3, 9 }, new int[] { 9, 3 }) == 1);
    }
}

代码解释

  1. solution(int N, int[] A, int[] B) :这个方法用来计算最小的操作次数。首先,调用 countChanges(A, B) 计算不反转数组 A 的情况下,A 到 B 的最小操作次数。然后,我们将 A 数组进行反转,调用 countChanges(reversedA, B) 计算反转后的 A 到 B 的操作次数。最后,我们返回两种操作次数中的最小值,并且反转操作本身算作一次操作,所以结果加 1。
  2. countChanges(int[] A, int[] B) :这个辅助方法用来计算数组 A 和 B 中不相同的位置的个数。因为每个不同的元素都需要进行一次修改,所以返回的就是修改次数。
  3. main 方法:在主函数中,我们通过几个测试用例验证了算法的正确性。

复杂度分析

  • 时间复杂度:主要的操作是在计算数组 A 和 B 的不同元素个数上,复杂度是 O(N),其中 N 是数组的长度。由于我们只进行了一次反转和两次计数,因此总的时间复杂度是 O(N)。
  • 空间复杂度:由于我们额外使用了一个反转后的数组 reversedA,空间复杂度是 O(N)。

总结

这道题考察了如何通过两种操作(反转数组和修改元素)来最小化转换次数。通过暴力方法,遍历数组计算不同位置的元素个数,我们能够轻松求得最小操作次数。该问题的难点在于如何灵活使用反转操作来减少后续的修改次数,从而达到最优解。

希望通过本篇文章,能够帮助大家更好地理解如何分析问题,并通过简单的算法来解决实际问题。如果你还有任何疑问,欢迎在评论区留言。