[LeetCode] 1590. Make Sum Divisible by P
Given an array of positive integers nums
, remove the smallest subarray (possibly empty) such that the sum of the remaining elements is divisible by p
. It is not allowed to remove the whole array.
Return the length of the smallest subarray that you need to remove, or -1
if it's impossible.
A subarray is defined as a contiguous block of elements in the array.
Example 1:
Input: nums = [3,1,4,2], p = 6 Output: 1 Explanation: The sum of the elements in nums is 10, which is not divisible by 6. We can remove the subarray [4], and the sum of the remaining elements is 6, which is divisible by 6.
Example 2:
Input: nums = [6,3,5,2], p = 9 Output: 2 Explanation: We cannot remove a single element to get a sum divisible by 9. The best way is to remove the subarray [5,2], leaving us with [6,3] with sum 9.
Example 3:
Input: nums = [1,2,3], p = 3 Output: 0 Explanation: Here the sum is 6. which is already divisible by 3. Thus we do not need to remove anything.
Constraints:
1 <= nums.length <= 105
1 <= nums[i] <= 109
1 <= p <= 109
使数组和能被 P 整除。
给你一个正整数数组 nums,请你移除 最短 子数组(可以为 空),使得剩余元素的 和 能被 p 整除。 不允许 将整个数组都移除。
请你返回你需要移除的最短子数组的长度,如果无法满足题目要求,返回 -1 。
子数组 定义为原数组中连续的一组元素。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/make-sum-divisible-by-p
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路是前缀和。这算是前缀和类型的题目里比较麻烦的一道题,思路不难看出来但是里面有一些细节的实现不太容易。
题目问的是能否找到一个最短的子数组满足移除这个子数组之后,剩下的部分能被 P 整除。一个容易想到的 corner case 是如果整个数组的前缀和就能被 P 整除,那么直接返回 0 即可。
一般的 case 是,假设整个数组的前缀和 = sum,sum % p = remainder。我们需要找的是一个最短的子数组,他的和 sum2 = remainder,这样 sum - sum2 就能被 P 整除了。如下图,我们找一个最短的黄色的部分,然后黄色的部分 % P = remainder 即可。
[x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x]
注意我们在累加前缀和的时候,每次加一个数字,都要 % P,这样使得 sum2 总是落在 [0, p) 这个范围内。
时间O(n)
空间O(n)
Java实现
1 class Solution { 2 public int minSubarray(int[] nums, int p) { 3 long sum = 0; 4 for (int num : nums) { 5 sum += num; 6 } 7 int remainder = (int) (sum % p); 8 // corner case 9 if (remainder == 0) { 10 return 0; 11 } 12 13 // normal case 14 int n = nums.length; 15 int res = n; 16 int sum2 = 0; 17 HashMap<Integer, Integer> map = new HashMap<>(); 18 map.put(0, -1); 19 for (int i = 0;i < n; i++) { 20 sum2 = (sum2 + nums[i]) % p; 21 map.put(sum2, i); 22 int j = map.getOrDefault((sum2 - remainder + p) % p, -n); 23 res = Math.min(res, i - j); 24 } 25 return res < n ? res : -1; 26 } 27 }