
文章目录
【华为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的连续子数组的最大和。
我们可以用两种方法来解决:
- 暴力解法:遍历所有可能的长度为k的子数组,计算每个子数组的和,找出最大值
- 滑动窗口优化解法:使用滑动窗口技术,只需要一次遍历即可
解法一:暴力解法
思路
- 遍历数组中每个可能的起始位置
- 对于每个起始位置,计算长度为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机试,这类固定滑窗问题是常考题型,掌握滑动窗口的思想和实现方式非常重要。