华为OD机试 - 阿里巴巴找黄金宝箱(V) - 滑动窗口(Java 2024 E卷 100分)

题目描述

阿里巴巴发现编号从 0 0 0 N − 1 N-1 N1 的宝箱,每个宝箱上贴有一个数字。给定咒语数字 k k k ( k < N k < N k<N),需要找出连续 k k k 个宝箱数字和的最大值。

输入描述

  • 第一行:数字字符串,用逗号分隔,如 2,10,-3,-8,40,5
  • 第二行:咒语数字 k k k,如 4

输出描述
连续 k k k 个宝箱数字和的最大值

输入输出示例

示例 1:
输入:

2,10,-3,-8,40,5
4

输出:

39

解释:
初始窗口 [ 2 , 10 , − 3 , − 8 ] [2,10,-3,-8] [2,10,3,8] 和为 1 1 1,移动窗口得到 [ 10 , − 3 , − 8 , 40 ] [10,-3,-8,40] [10,3,8,40] 和为 39 39 39(最大值),后续窗口和为 34 34 34

示例 2:
输入:

8
1

输出:

8

解释:
仅一个数字且 k = 1 k=1 k=1,直接输出该数字。

示例 3:
输入:

-1,-2,-3,-4
2

输出:

-3

解释:
初始窗口 [ − 1 , − 2 ] [-1,-2] [1,2] 和为 − 3 -3 3(最大值),后续窗口和为 − 5 -5 5 − 7 -7 7

解题思路

  1. 问题分析

    • 需要在长度为 N N N 的数组中,找到所有长度为 k k k 的连续子数组和的最大值。
    • 数组元素范围大( − 1 0 4 -10^4 104 1 0 4 10^4 104),需高效算法。
  2. 算法选择

    • 滑动窗口:维护一个长度为 k k k 的窗口,通过前一个窗口和计算当前窗口和,避免重复计算。
    • 时间复杂度优化至 O ( N ) O(N) O(N)
  3. 步骤详解

    1. 将输入字符串转换为整数数组。
    2. 计算初始窗口 [ 0 , k − 1 ] [0, k-1] [0,k1] 的和 w i n d o w _ s u m window\_sum window_sum
    3. 遍历数组从 k k k N − 1 N-1 N1
      • 更新窗口和: w i n d o w _ s u m + = n u m s [ i ] − n u m s [ i − k ] window\_sum += nums[i] - nums[i-k] window_sum+=nums[i]nums[ik]
      • 比较并更新最大值 m a x _ s u m max\_sum max_sum

代码实现

Java
import java.util.Arrays;
import java.util.Scanner;

public class 阿里巴巴找黄金宝箱V {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int[] array = Arrays.stream(scanner.nextLine().split(",")).mapToInt(Integer::parseInt).toArray();
        int k = Integer.parseInt(scanner.nextLine());
        int sum = 0;
        for (int i = 0; i < k; i++) {
            sum += array[i];
        }
        int res = sum;
        int right = k - 1;
        int left = 0;
        while (right + 1 < array.length) {
            sum += array[right + 1];
            sum -= array[left];
            res = Math.max(res, sum);
            left++;
            right++;
        }
        System.out.println(res);
    }
}
import java.util.Arrays;

public class Solution {
    public int maxSum(String numsStr, int k) {
        int[] nums = Arrays.stream(numsStr.split(","))
                          .mapToInt(Integer::parseInt)
                          .toArray();
        int windowSum = 0;
        for (int i = 0; i < k; i++) {
            windowSum += nums[i];
        }
        int maxSum = windowSum;
        for (int i = k; i < nums.length; i++) {
            windowSum += nums[i] - nums[i - k];
            maxSum = Math.max(maxSum, windowSum);
        }
        return maxSum;
    }
}
Python
def max_sum(nums_str: str, k: int) -> int:
    nums = list(map(int, nums_str.split(',')))
    window_sum = sum(nums[:k])
    max_sum = window_sum
    for i in range(k, len(nums)):
        window_sum += nums[i] - nums[i - k]
        max_sum = max(max_sum, window_sum)
    return max_sum
C++
#include 
#include 
#include 
#include 

using namespace std;

class Solution {
public:
    int maxSum(string numsStr, int k) {
        vector<int> nums;
        stringstream ss(numsStr);
        string num;
        while (getline(ss, num, ',')) {
            nums.push_back(stoi(num));
        }
        int windowSum = 0;
        for (int i = 0; i < k; i++) {
            windowSum += nums[i];
        }
        int maxSum = windowSum;
        for (int i = k; i < nums.size(); i++) {
            windowSum += nums[i] - nums[i - k];
            maxSum = max(maxSum, windowSum);
        }
        return maxSum;
    }
};
JavaScript
function maxSum(numsStr, k) {
    const nums = numsStr.split(',').map(Number);
    let windowSum = nums.slice(0, k).reduce((a, b) => a + b, 0);
    let maxSum = windowSum;
    for (let i = k; i < nums.length; i++) {
        windowSum += nums[i] - nums[i - k];
        maxSum = Math.max(maxSum, windowSum);
    }
    return maxSum;
}

复杂度分析

  • 时间复杂度 O ( N ) O(N) O(N)
    每个元素被访问两次(初始窗口和滑动窗口各一次)。
  • 空间复杂度 O ( N ) O(N) O(N)
    存储输入数组(若直接遍历字符串可优化至 O ( 1 ) O(1) O(1))。

测试用例示例

测试用例 1:
输入:

2,10,-3,-8,40,5
4

预期输出:

39

测试用例 2:
输入:

8
1

预期输出:

8

测试用例 3:
输入:

-1,-2,-3,-4
2

预期输出:

-3

问题总结

  • 核心要点:滑动窗口高效计算固定长度子数组和的最大值。
  • 解题关键:通过前一个窗口和递推当前窗口和,避免重复计算。
  • 优化方向:直接遍历输入字符串可节省空间(需处理负数)。
  • 适用性:适用于任何需要固定长度子数组统计的问题。

你可能感兴趣的:(华为OD,机试,算法,Java,Python)