【华为OD】阿里巴巴找黄金宝箱

文章目录

【华为OD】阿里巴巴找黄金宝箱

题目描述

一贫如洗的樵夫阿里巴巴在去砍柴的路上,无意中发现了强盗集团的藏宝地,藏宝地有编号从0-N的箱子,每个箱子上面贴有一个数字。阿里巴巴念出一个咒语数字k (k < N),找出连续k个宝箱数字和的最大值,并输出该最大值。

输入输出格式

输入

  • 第一行输入一个数字字串,数字之间使用逗号分隔,例如:2,10,-3,-8,40,5
  • 1 ≤ 字串中数字的个数 ≤ 100000,-10000 ≤ 每个数字 ≤ 10000
  • 第二行输入咒语数字k,例如:4,咒语数字大小小于宝箱的个数

输出

连续k个宝箱数字和的最大值,例如:39

示例

示例一

输入:

复制代码
2,10,-3,-8,40,5
4

输出:

复制代码
39

示例二

输入:

复制代码
8
1

输出:

复制代码
8

解题思路

这是一个典型的滑动窗口问题,需要找到长度为k的连续子数组的最大和。

我们可以用两种方法来解决:

  1. 暴力解法:遍历所有可能的长度为k的子数组,计算每个子数组的和,找出最大值
  2. 滑动窗口优化解法:使用滑动窗口技术,只需要一次遍历即可

解法一:暴力解法

思路

  • 遍历数组中每个可能的起始位置
  • 对于每个起始位置,计算长度为k的子数组和
  • 记录最大值

Java实现

java 复制代码
import java.util.Scanner;

public class Solution1 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String[] nums = scanner.nextLine().split(",");
        int k = scanner.nextInt();
        
        int[] arr = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            arr[i] = Integer.parseInt(nums[i]);
        }
        
        int maxSum = Integer.MIN_VALUE;
        
        // 暴力遍历所有长度为k的子数组
        for (int i = 0; i <= arr.length - k; i++) {
            int currentSum = 0;
            for (int j = i; j < i + k; j++) {
                currentSum += arr[j];
            }
            maxSum = Math.max(maxSum, currentSum);
        }
        
        System.out.println(maxSum);
        scanner.close();
    }
}

Python实现

python 复制代码
def find_max_sum_brute_force():
    nums = list(map(int, input().split(',')))
    k = int(input())
    
    max_sum = float('-inf')
    
    # 暴力遍历所有长度为k的子数组
    for i in range(len(nums) - k + 1):
        current_sum = sum(nums[i:i+k])
        max_sum = max(max_sum, current_sum)
    
    print(max_sum)

find_max_sum_brute_force()

C++实现

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <climits>
#include <algorithm>

using namespace std;

int main() {
    string line;
    getline(cin, line);
    
    vector<int> nums;
    stringstream ss(line);
    string num;
    
    while (getline(ss, num, ',')) {
        nums.push_back(stoi(num));
    }
    
    int k;
    cin >> k;
    
    int maxSum = INT_MIN;
    
    // 暴力遍历所有长度为k的子数组
    for (int i = 0; i <= (int)nums.size() - k; i++) {
        int currentSum = 0;
        for (int j = i; j < i + k; j++) {
            currentSum += nums[j];
        }
        maxSum = max(maxSum, currentSum);
    }
    
    cout << maxSum << endl;
    return 0;
}

解法二:滑动窗口优化解法

思路

  • 首先计算前k个元素的和作为初始窗口
  • 然后滑动窗口:移除窗口左边的元素,添加窗口右边的新元素
  • 在滑动过程中记录最大和

Java实现

java 复制代码
import java.util.Scanner;

public class Solution2 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String[] nums = scanner.nextLine().split(",");
        int k = scanner.nextInt();
        
        int[] arr = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            arr[i] = Integer.parseInt(nums[i]);
        }
        
        // 计算第一个窗口的和
        int windowSum = 0;
        for (int i = 0; i < k; i++) {
            windowSum += arr[i];
        }
        
        int maxSum = windowSum;
        
        // 滑动窗口
        for (int i = k; i < arr.length; i++) {
            windowSum = windowSum - arr[i - k] + arr[i];
            maxSum = Math.max(maxSum, windowSum);
        }
        
        System.out.println(maxSum);
        scanner.close();
    }
}

Python实现

python 复制代码
def find_max_sum_sliding_window():
    nums = list(map(int, input().split(',')))
    k = int(input())
    
    # 计算第一个窗口的和
    window_sum = sum(nums[:k])
    max_sum = window_sum
    
    # 滑动窗口
    for i in range(k, len(nums)):
        window_sum = window_sum - nums[i - k] + nums[i]
        max_sum = max(max_sum, window_sum)
    
    print(max_sum)

find_max_sum_sliding_window()

C++实现

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>

using namespace std;

int main() {
    string line;
    getline(cin, line);
    
    vector<int> nums;
    stringstream ss(line);
    string num;
    
    while (getline(ss, num, ',')) {
        nums.push_back(stoi(num));
    }
    
    int k;
    cin >> k;
    
    // 计算第一个窗口的和
    int windowSum = 0;
    for (int i = 0; i < k; i++) {
        windowSum += nums[i];
    }
    
    int maxSum = windowSum;
    
    // 滑动窗口
    for (int i = k; i < (int)nums.size(); i++) {
        windowSum = windowSum - nums[i - k] + nums[i];
        maxSum = max(maxSum, windowSum);
    }
    
    cout << maxSum << endl;
    return 0;
}

复杂度分析

解法一(暴力解法)

  • 时间复杂度:O(n×k),其中n是数组长度
  • 空间复杂度:O(1)

解法二(滑动窗口)

  • 时间复杂度:O(n),其中n是数组长度
  • 空间复杂度:O(1)

总结

滑动窗口是解决这类连续子数组问题的经典方法,相比暴力解法有明显的性能优势。在实际面试中,建议优先考虑滑动窗口解法,它不仅时间复杂度更优,也体现了对算法优化的理解。

对于华为OD机试,这类固定滑窗问题是常考题型,掌握滑动窗口的思想和实现方式非常重要。

相关推荐
玛卡巴卡ldf8 小时前
【LeetCode 手撕算法】(多维动态规划)不同路径、最小路径和、最长回文子串、最长公共子序列、编辑距离
java·数据结构·算法·leetcode·动态规划·力扣
被AI抢饭碗的人8 小时前
算法:数据结构
数据结构·算法
_深海凉_8 小时前
LeetCode热题100-验证二叉搜索树
算法·leetcode·职场和发展
shehuiyuelaiyuehao8 小时前
算法27,二维前缀和
开发语言·python·算法
蒟蒻的贤8 小时前
编译原理里的冲突到底是什么?
考研·算法
_深海凉_9 小时前
LeetCode热题100-二叉树的右视图
算法·leetcode·职场和发展
计算机安禾9 小时前
【c++面向对象编程】第29篇:定位new(placement new):在指定内存上构造对象
开发语言·c++·算法
淞綰9 小时前
c语言的练习-字符串的练习-寻找最长连续字符以及出现次数
c语言·数据结构·学习·算法·c语言的练习
计算机安禾9 小时前
【c++面向对象编程】第27篇:空类的大小为什么是1?——C++对象标识的秘密
开发语言·c++·算法
信竞星球_少儿编程题库9 小时前
2026年全国信息素养大赛算法应用主题赛 丝路新城 Python 模拟卷(三)
开发语言·python·算法