[LeetCode] Continuous Subarray Sum 連續的子陣列之和
Given a list of non-negative numbers and a target integer k, write a function to check if the array has a continuous subarray of size at least 2 that sums up to the multiple of k, that is, sums up to n*k where n is also an integer.
Example 1:
Input: [23, 2, 4, 6, 7], k=6 Output: True Explanation:Because [2, 4] is a continuous subarray of size 2 and sums up to 6.
Example 2:
Input: [23, 2, 6, 4, 7], k=6 Output: True Explanation: Because [23, 2, 6, 4, 7] is an continuous subarray of size 5 and sums up to 42.
Note:
- The length of the array won't exceed 10,000.
- You may assume the sum of all the numbers is in the range of a signed 32-bit integer.
這道題給了我們一個數組和一個數字k,讓我們求是否存在這樣的一個連續的子陣列,該子陣列的陣列之和可以整除k。遇到除法問題,我們肯定不能忘了除數為0的情況等處理。還有就是我們如何能快速的遍歷所有的子陣列,並且求和,我們肯定不能完全的暴力破解,這樣OJ肯定不答應。我們需要適當的優化,如果是刷題老司機的話,遇到這種求子陣列或者子矩陣之和的題,應該不難想到要建立累加和陣列或者累加和矩陣來做。沒錯,這道題也得這麼做,我們要遍歷所有的子陣列,然後利用累加和來快速求和。在得到每個子陣列之和時,我們先和k比較,如果相同直接返回true,否則再判斷,若k不為0,且sum能整除k,同樣返回true,最後遍歷結束返回false,參見程式碼如下:
解法一:
class Solution { public: bool checkSubarraySum(vector<int>& nums, int k) { for (int i = 0; i < nums.size(); ++i) { int sum = nums[i]; for (int j = i + 1; j < nums.size(); ++j) { sum += nums[j]; if (sum == k) return true; if (k != 0 && sum % k == 0) return true; } } return false; } };
下面這種方法用了些技巧,那就是,若數字a和b分別除以數字c,若得到的餘數相同,那麼(a-b)必定能夠整除c。這裡就不證明了,博主也不會證明。明白了這條定理,那麼我們用一個集合set來儲存所有出現過的餘數,如果當前的累加和除以k得到的餘數在set中已經存在了,那麼說明之前必定有一段子陣列和可以整除k。需要注意的是k為0的情況,由於無法取餘,我們就把當前累加和放入set中。還有就是題目要求子陣列至少需要兩個數字,那麼我們需要一個變數pre來記錄之前的和,我們每次存入set中的是pre,而不是當前的累積和,參見程式碼如下:
解法二:
class Solution { public: bool checkSubarraySum(vector<int>& nums, int k) { int n = nums.size(), sum = 0, pre = 0; unordered_set<int> st; for (int i = 0; i < n; ++i) { sum += nums[i]; int t = (k == 0) ? sum : (sum % k); if (st.count(t)) return true; st.insert(pre); pre = t; } return false; } };
既然set可以做,一般來說用雜湊表也可以做,這裡我們建立餘數和當前位置之間的對映,由於有了位置資訊,我們就不需要pre變量了,之前用儲存的座標和當前位置i比較判斷就可以了,參見程式碼如下:
解法三:
class Solution { public: bool checkSubarraySum(vector<int>& nums, int k) { int n = nums.size(), sum = 0; unordered_map<int, int> m{{0,-1}}; for (int i = 0; i < n; ++i) { sum += nums[i]; int t = (k == 0) ? sum : (sum % k); if (m.count(t)) { if (i - m[t] > 1) return true; } else m[t] = i; } return false; } };
參考資料: