刷题笔记:448最大连续子数组和问题 | 豆包MarsCode AI刷题

129 阅读4分钟

问题描述

小C拿到了一个数组,他可以进行最多一次操作:将一个元素修改为任意给定的xx。小C想知道,经过这次修改后,能够得到的连续子数组的最大和是多少。

解题思路

  1. Kadane算法:首先,我们可以使用Kadane算法来计算不进行任何修改时的最大子数组和。Kadane算法的时间复杂度为O(n)。

  2. 考虑修改操作:接下来,我们需要考虑如何利用一次修改操作来最大化子数组的和。我们可以遍历数组中的每个元素,假设将其修改为 x,然后计算修改后的最大子数组和。

  3. 计算修改后的最大和:对于每个元素 a[i],我们可以计算以下三种情况的最大和:

    • 不修改任何元素,直接使用Kadane算法的结果。
    • 修改 a[i] 为 x,然后计算包含 a[i] 的最大子数组和。
    • 修改 a[i] 为 x,然后计算不包含 a[i] 的最大子数组和。
  4. 取最大值:最终的结果是上述三种情况的最大值。

代码实现

public class Main {
    public static int solution(int n, int x, int[] a) {
        // 使用Kadane算法计算不修改时的最大子数组和
        int maxSumWithoutChange = kadane(a);

        int maxSumWithChange = Integer.MIN_VALUE;

        // 遍历数组中的每个元素,假设将其修改为 x
        for (int i = 0; i < n; i++) {
            int originalValue = a[i];
            a[i] = x; // 修改当前元素为 x

            // 计算修改后的最大子数组和
            int currentMaxSum = kadane(a);

            // 恢复原值
            a[i] = originalValue;

            // 更新最大值
            maxSumWithChange = Math.max(maxSumWithChange, currentMaxSum);
        }

        // 返回不修改和修改后的最大值
        return Math.max(maxSumWithoutChange, maxSumWithChange);
    }

    // Kadane算法计算最大子数组和
    private static int kadane(int[] a) {
        int maxEndingHere = a[0];
        int maxSoFar = a[0];

        for (int i = 1; i < a.length; i++) {
            maxEndingHere = Math.max(a[i], maxEndingHere + a[i]);
            maxSoFar = Math.max(maxSoFar, maxEndingHere);
        }

        return maxSoFar;
    }

    public static void main(String[] args) {
        System.out.println(solution(5, 10, new int[] { 5, -1, -5, -3, 2 }) == 15);
        System.out.println(solution(2, -3, new int[] { -5, -2 }) == -2);
        System.out.println(solution(6, 10, new int[] { 4, -2, -11, -1, 4, -1 }) == 15);
    }
}

Kadane算法介绍

Kadane's 算法是一种用于解决最大子数组和问题的高效算法。这个问题要求在一个整数数组中找到一个连续子数组(至少包含一个数字),使得该子数组的元素之和最大。例如,给定数组 [-2, 1, -3, 4, -1, 2, 1, -5, 4],其连续子数组 [4, -1, 2, 1] 的和为 6,这是所有可能的子数组中最大的。

Kadane's 算法的核心思想

  • 局部最优解:在遍历过程中,我们维护一个变量 current_max 来记录当前子数组的最大和。
  • 全局最优解:同时维护另一个变量 global_max 来记录到目前为止遇到的最大子数组和。
  • 在每一步,我们决定是否将当前元素加入现有的子数组中,或者从当前元素开始一个新的子数组。

算法步骤

  1. 初始化两个变量 current_maxglobal_max,都设置为数组的第一个元素。
  2. 遍历数组中的每个元素:
    • 对于每个元素,更新 current_max 为其自身与 current_max + 当前元素 中较大的值。
    • 如果 current_max 大于 global_max,则更新 global_max
  3. 遍历结束后,global_max 即为所求的最大子数组和。

Java 实现示例

public class KadanesAlgorithm {
    public static int maxSubArraySum(int[] nums) {
        if (nums == null || nums.length == 0) {
            throw new IllegalArgumentException("Array must not be null or empty");
        }

        // 初始化当前最大子数组和以及全局最大子数组和
        int currentMax = nums[0];
        int globalMax = nums[0];

        // 从第二个元素开始遍历
        for (int i = 1; i < nums.length; i++) {
            // 更新当前最大子数组和
            currentMax = Math.max(nums[i], currentMax + nums[i]);
            // 更新全局最大子数组和
            if (currentMax > globalMax) {
                globalMax = currentMax;
            }
        }

        return globalMax;
    }

    public static void main(String[] args) {
        int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
        System.out.println("Maximum subarray sum is: " + maxSubArraySum(nums));
    }
}

在这个实现中:

  • currentMax 被用来跟踪当前子数组的最大和。
  • globalMax 保存了迄今为止发现的最大子数组和。
  • 每次迭代时,我们决定是继续累加当前元素还是重新开始一个新的子数组,这取决于 currentMax + nums[i]nums[i] 哪个更大。

时间复杂度与空间复杂度

  • 时间复杂度:O(n),因为算法只需要遍历整个数组一次。
  • 空间复杂度:O(1),因为我们只使用了常数级别的额外空间。