[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 }

 

LeetCode 题目总结

posted @ 2023-03-10 11:37  CNoodle  阅读(48)  评论(0编辑  收藏  举报