LeetCode Python, Java, C++  >  3689. 最大子数组总和 I  >  已支持 Python, Java, JavaScript, C++, C#, Go, Ruby, Rust, Kotlin, Swift  >  GitHub

力扣链接:3689. 最大子数组总和 I,难度等级:中等。

给你一个长度为 n 的整数数组 nums 和一个整数 k。

你需要恰好选择 k 个 nums 的非空子数组 nums[l..r]。子数组可以重叠,并且完全相同的子数组(相同的 l 和 r)可以被多次选择。

子数组 nums[l..r] 的 值 定义为:max(nums[l..r]) - min(nums[l..r])。

总和 是所有被选中的子数组的 值 之和。

返回你能达到的 最大 可能总和。

子数组 是数组中连续的 非空 元素序列。

示例 1:

输入: nums = [1,3,2], k = 2

输出: 4

解释:

一种最优方案是:
- 选择 nums[0..1] = [1, 3]。最大值是 3,最小值是 1,产生的值为 3 - 1 = 2。
- 选择 nums[0..2] = [1, 3, 2]。最大值仍然是 3,最小值仍然是 1,因此值也为 3 - 1 = 2。
将这些值相加得到 2 + 2 = 4。

示例 2:

输入: nums = [4,2,5,1], k = 3

输出: 12

解释:

一种最优方案是:
- 选择 nums[0..3] = [4, 2, 5, 1]。最大值是 5,最小值是 1,产生的值为 5 - 1 = 4。
- 选择 nums[0..3] = [4, 2, 5, 1]。最大值是 5,最小值是 1,所以值也为 4。
- 选择 nums[2..3] = [5, 1]。最大值是 5,最小值是 1,所以值再次为 4。
将这些值相加得到 4 + 4 + 4 = 12。

约束:

  • 1 <= n == nums.length <= 5 * 10^4
  • 0 <= nums[i] <= 10^9
  • 1 <= k <= 10^5
相关标签

数组 贪心算法

提示 1

Choose the whole subarray k times.

思路

问题要求我们准确选择 k 个子数组,使得所有选定子数组的 max(subarray) - min(subarray) 之和最大化。我们可以选择重叠的子数组,甚至可以多次选择完全相同的子数组。

这里的一个关键观察是,对于任何子数组 nums[l..r],其最大值永远不会超过整个数组的全局最大值,其最小值也永远不会小于整个数组的全局最小值。在数学上,max(nums[l..r]) <= max(nums) 且 min(nums[l..r]) >= min(nums)。

因此,任何子数组的值的上限都是 max(nums) - min(nums)。因为我们想要最大化恰好 k 个子数组的总和,而且题目允许我们多次选择完全相同的子数组,所以最优策略就是直接把整个数组 nums 选择 k 次。

这个问题就简化成了:找到数组的全局最大值和全局最小值,计算它们的差值,然后将该差值乘以 k。

👋 站长寄语:我还为你开发了 coder.id - 打造程序员个人IP, 包含作品集、简历和博客等,助您顺利拿到 Offer!

步骤

  1. 寻找全局极值: 遍历数组 nums 一次,找到最大值(maxVal)和最小值(minVal)。
  2. 计算差值: 从全局最大值中减去全局最小值,得到单个子数组可能产生的最大值(maxVal - minVal)。
  3. 乘以 k: 因为我们可以把整个数组选择 k 次,所以将差值乘以 k 即可得到最大总和。
  4. 处理大数: 结果可能高达 10^5 * 10^9 = 10^{14},这超出了 32 位有符号整数的限制。确保在计算时使用 64 位整数(例如 Java/C# 中的 long,C++ 中的 long long)以防止溢出。

复杂度

时间复杂度

O(N)

空间复杂度

O(1)

解释

  • 时间复杂度: O(N),其中 N 是数组的长度。我们只需要遍历数组一次即可找到最大值和最小值。
  • 空间复杂度: O(1)。我们只使用了几个额外的变量来跟踪最大值和最小值,这需要常数级别的额外空间。

Python #

class Solution:
    def maxTotalValue(self, nums: List[int], k: int) -> int:
        # We can find the global maximum and minimum of the entire array using built-in functions.
        # The time complexity of max() and min() is O(N) each, making the total O(N).
        max_val = max(nums)
        min_val = min(nums)

        # The optimal approach is to pick the entire array exactly k times.
        # This gives us the absolute maximum difference possible.
        # Python automatically handles arbitrarily large integers, so no overflow concerns.
        return k * (max_val - min_val)

Java #

class Solution {
    public long maxTotalValue(int[] nums, int k) {
        // Initialize max and min values with the first element of the array
        int maxVal = nums[0];
        int minVal = nums[0];

        // Iterate through the array to find the global maximum and minimum
        for (int num : nums) {
            if (num > maxVal) {
                maxVal = num;
            }
            if (num < minVal) {
                minVal = num;
            }
        }

        // The maximum value for a single subarray is maxVal - minVal.
        // We multiply this by k to get the maximum total value.
        // Cast k to a long before multiplication to prevent 32-bit integer overflow.
        return (long) k * (maxVal - minVal);
    }
}

JavaScript #

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var maxTotalValue = function(nums, k) {
    // Initialize the global extreme values
    let maxVal = nums[0];
    let minVal = nums[0];

    // Iterate through the array once to find the global max and min.
    // We do not use Math.max(...nums) because it can throw a Maximum Call Stack Size 
    // Exceeded error if the array is very large (e.g. 50,000 elements).
    for (let i = 1; i < nums.length; i++) {
        if (nums[i] > maxVal) maxVal = nums[i];
        if (nums[i] < minVal) minVal = nums[i];
    }

    // Return the difference multiplied by k.
    // JS numbers are double-precision floats, which safely represent integers up to 2^53 - 1.
    // Our max possible answer is 10^14, which fits comfortably without needing BigInt.
    return k * (maxVal - minVal);
};

C++ #

class Solution {
public:
    long long maxTotalValue(vector<int>& nums, int k) {
        // Initialize max and min with the first element
        int maxVal = nums[0];
        int minVal = nums[0];

        // Find the global maximum and minimum in the array
        for (int num : nums) {
            if (num > maxVal) maxVal = num;
            if (num < minVal) minVal = num;
        }

        // We choose the entire array k times.
        // The maximum possible value is 10^14, which exceeds the 32-bit int limit.
        // So we cast k to long long to perform 64-bit arithmetic.
        return (long long) k * (maxVal - minVal);
    }
};

C# #

public class Solution {
    public long MaxTotalValue(int[] nums, int k) {
        // Initialize the extreme values using the first element
        int maxVal = nums[0];
        int minVal = nums[0];

        // Iterate over all elements to find the global maximum and minimum
        foreach (int num in nums) {
            if (num > maxVal) maxVal = num;
            if (num < minVal) minVal = num;
        }

        // Since max difference is 10^9 and k is 10^5, the product can be 10^14.
        // We explicitly cast to long to avoid 32-bit integer overflow.
        return (long) k * (maxVal - minVal);
    }
}

Go #

func maxTotalValue(nums []int, k int) int64 {
    // Start by assuming the first element is both the max and the min
    maxVal := nums[0]
    minVal := nums[0]

    // Make a single pass through the array to update max and min
    for _, num := range nums {
        if num > maxVal {
            maxVal = num
        }
        if num < minVal {
            minVal = num
        }
    }

    // Calculate the difference and multiply by k.
    // Cast everything to int64 to avoid overflow since the answer can be up to 10^14.
    return int64(k) * int64(maxVal - minVal)
}

Ruby #

# @param {Integer[]} nums
# @param {Integer} k
# @return {Integer}
def max_total_value(nums, k)
    # Ruby arrays have highly optimized built-in methods for max and min.
    # We find the global maximum and minimum.
    max_val = nums.max
    min_val = nums.min

    # We can pick the entire array exactly k times to get the maximum sum.
    # Ruby automatically handles large integers seamlessly, so no overflow occurs.
    k * (max_val - min_val)
end

Rust #

impl Solution {
    pub fn max_total_value(nums: Vec<i32>, k: i32) -> i64 {
        // Initialize max and min with the first element of the array
        let mut max_val = nums[0];
        let mut min_val = nums[0];

        // Iterate through the array to find the global extreme values
        for &num in nums.iter() {
            if num > max_val { max_val = num; }
            if num < min_val { min_val = num; }
        }

        // Calculate the maximum difference
        let diff = (max_val - min_val) as i64;

        // Multiply by k using 64-bit integer arithmetic to prevent overflow
        (k as i64) * diff
    }
}

Kotlin #

class Solution {
    fun maxTotalValue(nums: IntArray, k: Int): Long {
        // Assume the first element is both the minimum and maximum
        var maxVal = nums[0]
        var minVal = nums[0]

        // Iterate through all elements to find the global max and min
        for (num in nums) {
            if (num > maxVal) maxVal = num
            if (num < minVal) minVal = num
        }

        // Cast k and the difference to Long to prevent 32-bit integer overflow.
        // The max possible value is 10^14.
        return k.toLong() * (maxVal - minVal).toLong()
    }
}

Swift #

class Solution {
    func maxTotalValue(_ nums: [Int], _ k: Int) -> Int {
        // Initialize extremes using the first element
        var maxVal = nums[0]
        var minVal = nums[0]

        // Single pass to find the global maximum and minimum
        for num in nums {
            if num > maxVal { maxVal = num }
            if num < minVal { minVal = num }
        }

        // Swift's Int is 64-bit on 64-bit platforms, which safely holds 10^14.
        // Simply return the difference multiplied by k.
        return k * (maxVal - minVal)
    }
}

其它语言

欢迎贡献代码到 GitHub repo -> 3689. 最大子数组总和 I。感谢!

打造你的开发者个人IP

  • 📄 简历 + 作品集 + 博客
  • 🌐 支持绑定自定义域名
  • ✨ 顶级子域名: https://yourname.coder.id

立即前往 coder.id 打造你的开发者个人IP →