【华为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机试,这类固定滑窗问题是常考题型,掌握滑动窗口的思想和实现方式非常重要。

相关推荐
塔中妖2 小时前
【华为OD】5G网络建设
网络·5g·华为od
bestadc2 小时前
LeetCode 几道 Promises 和 Time 的题目
javascript·算法·leetcode
墨染点香3 小时前
LeetCode 刷题【71. 简化路径】
算法·leetcode·职场和发展
知彼解己3 小时前
【算法】四大基础数据结构
数据结构·算法
老一岁3 小时前
希尔排序详解
数据结构·算法·排序算法
lifallen3 小时前
KafkaStreams 计算图节点设计:ProcessorNode、SourceNode、SinkNode
java·数据结构·算法·kafka·apache
索迪迈科技3 小时前
java后端工程师进修ing(研一版‖day42)
java·开发语言·学习·算法
名誉寒冰3 小时前
LeetCode 24 两两交换链表中的节点( 迭代与递归)
算法·leetcode·链表
小欣加油3 小时前
leetcode LCR 170.交易逆序对的总数
数据结构·c++·算法·leetcode·职场和发展·排序算法