【华为OD】阿里巴巴找黄金宝箱
文章目录
- 【华为OD】阿里巴巴找黄金宝箱
- 题目描述
- 输入输出格式
- 输入
- 输出
- 示例
- 示例一
- 示例二
- 解题思路
- 解法一:暴力解法
- 思路
- Java实现
- Python实现
- C++实现
- 解法二:滑动窗口优化解法
- 思路
- Java实现
- Python实现
- C++实现
- 复杂度分析
- 解法一(暴力解法)
- 解法二(滑动窗口)
- 总结
【华为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实现
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实现
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++实现
#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实现
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实现
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++实现
#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机试,这类固定滑窗问题是常考题型,掌握滑动窗口的思想和实现方式非常重要。