Description
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.
Example 4:
Input: nums = [1,2,3], p = 7
Output: -1
Explanation: There is no way to remove a subarray in order to get a sum divisible by 7.
Example 5:
Input: nums = [1000000000,1000000000,1000000000], p = 3
Output: 0
Constraints:
- 1 <= nums.length <= 105
- 1 <= nums[i] <= 109
- 1 <= p <= 109
分析
题目的意思是:给你一个数组,问最少移除多少个数使得剩下的子数组能够被p整除,如果不能则返回-1.这道题虽然直观,但是并不好做,我这里学习了一下别人的思路,可以转换一下思路找出一个子数组是的子数组的和等于sum(arr)%p.因此,我我们希望找到的是:
cur==sum(arr[0...j))
prev=sum(arr[0...i]))
sum(arr[i...j])==(cur-prev)%p==sum(arr)%p==target
最终,我们只需要找(cur-target)%p是否在prev出现过就行了,求满足条件的最短的子数组,然后删除就是最终的答案。
- 首先对arr求和,如果能被p整除,则直接返回为0;然后遍历数组,cur记录当前的前i个数的和,并除以p取余。然后按照上述的公式来计算是否存在prev数组等于(cu-target)%p,存在说明找到了一个,则求其长度,更新最短长度到res.如果不存在,则继续遍历,并记录当前的求和和索引的映射到字典中。
代码
class Solution:
def minSubarray(self, nums: List[int], p: int) -> int:
target=sum(nums)%p
if(target==0):
return 0
d={0:-1}
n=len(nums)
cur=0
res=n
for i in range(n):
cur=(cur+nums[i])%p
if(d.get((cur-target)%p) is not None):
res=min(res,i-d.get((cur-target)%p))
d[cur]=i
if(res<n):
return res
return -1