题目描述
给定一个非负整数数组 nums 和一个整数 k,要求找到数组中最长的连续子数组,使得该子数组的元素和恰好等于 k。返回该子数组的长度。如果不存在这样的子数组,返回 -1。
输入
- 一个非负整数数组 nums
- 一个整数 k
输出
- 返回满足条件的最长连续子数组的长度,如果不存在则返回 -1
示例
示例 1:
输入: nums = [1, -1, 5, -2, 3], k = 3
输出: 4
解释: 子数组 [1, -1, 5, -2] 的和为 3,且长度为 4。
示例 2:
输入: nums = [-2, -1, 2, 1], k = 1
输出: 2
解释: 子数组 [-1, 2] 的和为 1,且长度为 2。
示例 3:
输入: nums = [1, 2, 3], k = 9
输出: -1
解释: 没有和为 9 的连续子数组。
思路
我们可以使用前缀和(Prefix Sum)和哈希表(HashMap)来解决这个问题。具体步骤如下:
- 初始化一个哈希表 prefixSumMap,用于存储前缀和及其对应的索引。将前缀和为 0 的索引初始化为 -1,表示在数组开始之前的前缀和为 0。
- 初始化一个变量 maxLen 为 -1,用于记录最长连续子数组的长度。
- 初始化变量 currSum 为 0,用于记录当前的前缀和。
- 遍历数组 nums,在每个位置 i:
- 更新 currSum 为当前的前缀和:currSum += nums[i]。
- 计算目标前缀和 targetSum 为 currSum - k。
- 如果 targetSum 在哈希表中存在,则计算当前子数组的长度 length = i - prefixSumMap.get(targetSum)。
- 更新 maxLen 为 max(maxLen, length)。
- 如果 currSum 不在哈希表中,则将其添加到哈希表中,并记录索引 i。
- 返回 maxLen。
Java 代码解析
import java.util.HashMap;
import java.util.Map;
public class LongestSubarrayWithSumK {
public int maxLength(int[] nums, int k) {
Map<Integer, Integer> prefixSumMap = new HashMap<>();
prefixSumMap.put(0, -1);
int maxLen = -1;
int currSum = 0;
for (int i = 0; i < nums.length; i++) {
currSum += nums[i];
int targetSum = currSum - k;
if (prefixSumMap.containsKey(targetSum)) {
int length = i - prefixSumMap.get(targetSum);
maxLen = Math.max(maxLen, length);
}
if (!prefixSumMap.containsKey(currSum)) {
prefixSumMap.put(currSum, i);
}
}
return maxLen;
}
public static void main(String[] args) {
LongestSubarrayWithSumK solution = new LongestSubarrayWithSumK();
int[] nums1 = {1, -1, 5, -2, 3};
int k1 = 3;
System.out.println(solution.maxLength(nums1, k1)); // 输出: 4
int[] nums2 = {-2, -1, 2, 1};
int k2 = 1;
System.out.println(solution.maxLength(nums2, k2)); // 输出: 2
int[] nums3 = {1, 2, 3};
int k3 = 9;
System.out.println(solution.maxLength(nums3, k3)); // 输出: -1
}
}
C++ 代码解析
#include <iostream>
#include <unordered_map>
#include <vector>
#include <algorithm>
class Solution {
public:
int maxLength(std::vector<int>& nums, int k) {
std::unordered_map<int, int> prefixSumMap;
prefixSumMap[0] = -1;
int maxLen = -1;
int currSum = 0;
for (int i = 0; i < nums.size(); i++) {
currSum += nums[i];
int targetSum = currSum - k;
if (prefixSumMap.find(targetSum) != prefixSumMap.end()) {
int length = i - prefixSumMap[targetSum];
maxLen = std::max(maxLen, length);
}
if (prefixSumMap.find(currSum) == prefixSumMap.end()) {
prefixSumMap[currSum] = i;
}
}
return maxLen;
}
};
int main() {
Solution solution;
std::vector<int> nums1 = {1, -1, 5, -2, 3};
int k1 = 3;
std::cout << solution.maxLength(nums1, k1) << std::endl; // 输出: 4
std::vector<int> nums2 = {-2, -1, 2, 1};
int k2 = 1;
std::cout << solution.maxLength(nums2, k2) << std::endl; // 输出: 2
std::vector<int> nums3 = {1, 2, 3};
int k3 = 9;
std::cout << solution.maxLength(nums3, k3) << std::endl; // 输出: -1
return 0;
}
Python 代码解析
def maxLength(nums, k):
prefixSumMap = {0: -1}
maxLen = -1
currSum = 0
for i in range(len(nums)):
currSum += nums[i]
targetSum = currSum - k
if targetSum in prefixSumMap:
length = i - prefixSumMap[targetSum]
maxLen = max(maxLen, length)
if currSum not in prefixSumMap:
prefixSumMap[currSum] = i
return maxLen
# 测试用例
nums1 = [1, -1, 5, -2, 3]
k1 = 3
print(maxLength(nums1, k1)) # 输出: 4
nums2 = [-2, -1, 2, 1]
k2 = 1
print(maxLength(nums2, k2)) # 输出: 2
nums3 = [1, 2, 3]
k3 = 9
print(maxLength(nums3, k3)) # 输出: -1