Given an array nums and a target value k, find the maximum length of a subarray that sums to k. If there isn't one, return 0 instead.
Note:
The sum of the entire nums array is guaranteed to fit within the 32-bit signed integer range.
Example 1:
Input: nums =[1, -1, 5, -2, 3]
, k =3
Output: 4 Explanation: The subarray[1, -1, 5, -2]
sums to 3 and is the longest.Example 2:
Input: nums =[-2, -1, 2, 1]
, k =1
Output: 2 Explanation: The subarray[-1, 2]
sums to 1 and is the longest.
Follow Up:
Can you do it in O(n) time?
和等于 k 的最长子数组长度。题意是给一个数组和一个数字K,请你返回数组中最长的子数组,子数组的和需要等于K。
思路是前缀和prefix sum。跟其他几道前缀和的题类似,借着一个例子跑一下吧,
Input: nums =[1, -1, 5, -2, 3]
, k =3
Output: 4 Explanation: The subarray[1, -1, 5, -2]
sums to 3 and is the longest.
首先计算出数组的前缀和,数组变为[1, 0, 5, 3, 6]。接着遍历这个前缀和的数组,用hashmap记录<prefix sum, i> - 每个不同的前缀和和他们出现的位置。如果此时发现nums[i] - k在hashmap中,则res = Math.max(res, i - map.get(nums[i] - k))。这个例子里面,K = 3,前缀和跑到3的时候,发现3-3 = 0在hashmap里出现过,此时结算出来的res = 4。当然,之后在遍历到6的时候这里也能结算一次,但是因为这个地方结算的res的长度较短所以并不能更新结果。
时间O(n)
空间O(n)
Java实现
1 class Solution { 2 public int maxSubArrayLen(int[] nums, int k) { 3 // corner case 4 if (nums == null || nums.length == 0) { 5 return 0; 6 } 7 8 // normal case 9 int res = 0; 10 HashMap<Integer, Integer> map = new HashMap<>(); 11 map.put(0, -1); 12 for (int i = 1; i < nums.length; i++) { 13 nums[i] += nums[i - 1]; 14 } 15 for (int i = 0; i < nums.length; i++) { 16 if (map.containsKey(nums[i] - k)) { 17 res = Math.max(res, i - map.get(nums[i] - k)); 18 } 19 if (!map.containsKey(nums[i])) { 20 map.put(nums[i], i); 21 } 22 } 23 return res; 24 } 25 }