[LeetCode] 325. Maximum Size Subarray Sum Equals k 最大子數組之和為k


 


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?

 

這道題給我們一個一維數組nums,讓我們求和為k最大子數組,默認子數組必須連續,題目中提醒我們必須要在O(n)的時間復雜度完成,我試了下brute force無法通過OJ,那么根據題目中的提示標簽,我們需要用哈希表和累積和來做,關於累積和的用法可以參看我之前的博客Range Sum Query - Immutable,那么建立累積和的好處顯而易見,如果當前累積和正好等於k,那么從開頭到此位置的子數組就是一個符合要求的解,但不一定是最長的子數組,而使用哈希表來建立累積和和其坐標之間的映射,我們就從題目中給的例子進行分析:

nums: [1, -1, 5, -2, 3], k = 3

sums: [1, 0, 5, 3, 6]

我們可以看到累積和的第四個數字為3,和k相同,則說明前四個數字就是符合題意的一個子數組,再來看第二個例子:

nums: [-2, -1, 2, 1], k = 1

sums: [-2, -3, -1, 0]

我們發現累積和中沒有數字等於k,但是我們知道這個例子的答案是[-1, 2],那么我們看累積和數組的第一和第三個數字,我們是否能看出一些規律呢,沒錯,第三個數字-1減去k,得到第一個數字,這就是規律,這也是累積和求區間和的方法,但是由於累計和數組中可能會有重復數字,而哈希表的關鍵字不能相同,比如下面這個例子:

nums: [1, 0, -1], k = -1

sums: [1, 1, 0]

我們發現累積和數組的第一個和第二個數字都為1,那么如何建立映射呢,我想的是用一個一維數組將其都存起來,然后比較的話就比較數組中的第一個數字,當我們建立完哈希表后,開始遍歷這個哈希表,當累積和跟k相同時,我們更新res,不相同的話我們檢測當前值減去k得到的值在哈希表中存不存在,如果存在就更新結果,參見代碼如下:

 

解法一:

class Solution {
public:
    int maxSubArrayLen(vector<int>& nums, int k) {
        if (nums.empty()) return 0;
        int res = 0;
        unordered_map<int, vector<int>> m;
        m[nums[0]].push_back(0);
        vector<int> sum = nums;
        for (int i = 1; i < nums.size(); ++i) {
            sum[i] += sum[i - 1];
            m[sum[i]].push_back(i);
        }
        for (auto it : m) {
            if (it.first == k) res = max(res, it.second.back() + 1);
            else if (m.find(it.first - k) != m.end()) {
                res = max(res, it.second.back() - m[it.first - k][0]);
            }
        }
        return res;
    }
};

 

然而當我上網看大神們的解法時,才發現我圖樣圖森破,根本不需要我寫的那么復雜,我們不需要另外創建一個累積和的數組,而是直接用一個變量sum邊累加邊處理,而且我們哈希表也完全不用建立和一維數組的映射,只要保存第一個出現該累積和的位置,后面再出現直接跳過,這樣算下來就是最長的子數組,對於想出這解法的人,博主只想說,閣下何不隨風起,扶搖直上九萬里~參見代碼如下:

 

解法二:

class Solution {
public:
    int maxSubArrayLen(vector<int>& nums, int k) {
        int sum = 0, res = 0;
        unordered_map<int, int> m;
        for (int i = 0; i < nums.size(); ++i) {
            sum += nums[i];
            if (sum == k) res = i + 1;
            else if (m.count(sum - k)) res = max(res, i - m[sum - k]);
            if (!m.count(sum)) m[sum] = i;
        }
        return res;
    }
};

 

類似題目:

Minimum Size Subarray Sum

Range Sum Query - Immutable

 

參考資料:

https://leetcode.com/problems/maximum-size-subarray-sum-equals-k/

https://leetcode.com/discuss/77879/o-n-super-clean-9-line-java-solution-with-hashmap

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM