首先思考要移除的子陣列有甚麼性質。令 s 為陣列 nums 的總和、sremove 為要移除的子陣列的總和,則根據題意,s−sremovemodp=0。根據同餘的性質,由於移除後剩餘元素的總和能被 p 整除,因此 s 和 sremove 對 p 取模後的餘數相同,令其為 r,即 smodp=sremovemodp=r。
而要求一段連續的子陣列的總和,可以使用前綴和(Prefix Sum)來求解。令 s[i]=j=0∑inums[j],則 s[r]−s[l−1] 就是陣列 nums 的第 l 項到第 r 項的總和。由於我們只關心 smodp 的餘數,因此我們只需要維護前綴和對 p 取模後的餘數即可,即 s′[i]=s[i]modp。
classSolution: defminSubarray(self, nums: List[int], p: int) -> int: n = len(nums) r = sum(nums) % p if r == 0: return0 s = 0# prefix sum pos = {0: -1} ans = n for i, x inenumerate(nums): s = (s + x) % p if (s - r) % p in pos: ans = min(ans, i - pos[(s - r) % p]) pos[s] = i return ans if ans < n else -1
classSolution { public: intminSubarray(vector<int>& nums, int p){ int n = nums.size(); int r = 0; for (int x : nums) r = (r + x) % p; if (r == 0) return0; unordered_map<int, int> pos; pos[0] = -1; int ans = n; int s = 0; // prefix sum for (int i = 0; i < n; ++i) { s = (s + nums[i]) % p; if (pos.find((s - r + p) % p) != pos.end()) { ans = min(ans, i - pos[(s - r + p) % p]); } pos[s] = i; } return ans < n ? ans : -1; } };
寫在最後
Cover photo is remixed from @吃肥皂泡泡, thanks for their work!