使数组和能被 P 整除【LC1590】
给你一个正整数数组
nums
,请你移除 最短 子数组(可以为 空),使得剩余元素的 和 能被p
整除。 不允许 将整个数组都移除。请你返回你需要移除的最短子数组的长度,如果无法满足题目要求,返回
-1
。子数组 定义为原数组中连续的一组元素。
这种只差一点的感觉 真难受
-
思路
假设数组总和为 s u m sum sum,删除的数组范围为 [ l e f t , r i g h t ] [left,right] [left,right],那么可以通过前缀和数组计算出删除数组的和,记为 y y y,此时剩余元素之和为 s u m − y sum-y sum−y,如果剩余元素之和能够整除
p
,那么此时满足
( s u m − y ) % p = 0 y = s u m % p (sum-y)\%p=0 \\y = sum \% p (sum−y)%p=0y=sum%p
通过前缀和数组可得
p r e [ r i g h t ] − p r e [ l e f t ] = s u m % p p r e [ l e f t ] = ( p r e [ r i g h t ] − s u m ) % p pre[right]-pre[left] = sum \% p \\pre[left] =(pre[right]-sum) \% p pre[right]−pre[left]=sum%ppre[left]=(pre[right]−sum)%p
因此我们可以将前缀和放入哈希表中,哈希表存放前缀和及其对应的下标,然后对于每个right
,查找是否有符合的left
,有则更新最小长度 -
实现
为了防止越界,前缀和数组记录对
p
取余的结果class Solution { public int minSubarray(int[] nums, int p) { int n = nums.length, ans = n; var s = new int[n + 1]; for (int i = 0; i < n; ++i) s[i + 1] = (s[i] + nums[i]) % p; int x = s[n]; if (x == 0) return 0; // 移除空子数组(这行可以不要) var last = new HashMap<Integer, Integer>(); for (int i = 0; i <= n; ++i) { last.put(s[i], i); // 如果不存在,-n 可以保证 i-j >= n int j = last.getOrDefault((s[i] - x + p) % p, -n); ans = Math.min(ans, i - j); } return ans < n ? ans : -1; } } 作者:灵茶山艾府 链接:https://leetcode.cn/problems/make-sum-divisible-by-p/solutions/2158435/tao-lu-qian-zhui-he-ha-xi-biao-pythonjav-rzl0/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 复杂度
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n)
- 复杂度