持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 1 天,点击查看活动详情。
使数组和能被 P 整除
原题地址
给你一个正整数数组 nums,请你移除 最短 子数组(可以为 空),使得剩余元素的 和 能被 p 整除。 不允许 将整个数组都移除。
请你返回你需要移除的最短子数组的长度,如果无法满足题目要求,返回 -1 。
子数组 定义为原数组中连续的一组元素。
示例 1:
输入:nums = [3,1,4,2], p = 6
输出:1
解释:nums 中元素和为 10,不能被 p 整除。我们可以移除子数组 [4] ,剩余元素的和为 6 。
示例 2:
输入:nums = [6,3,5,2], p = 9
输出:2
解释:我们无法移除任何一个元素使得和被 9 整除,最优方案是移除子数组 [5,2] ,剩余元素为 [6,3],和为 9 。
示例 3:
输入:nums = [1,2,3], p = 3
输出:0
解释:和恰好为 6 ,已经能被 3 整除了。所以我们不需要移除任何元素。
示例 4:
输入:nums = [1,2,3], p = 7
输出:-1
解释:没有任何方案使得移除子数组后剩余元素的和被 7 整除。
示例 5:
输入:nums = [1000000000,1000000000,1000000000], p = 3
输出:0
提示:
1 <= nums.length <=1 <= nums[i] <=1 <= p <=
思路分析
- 以数组
[a,b,c,d]为例,和为sum,reminder为数组和与目标元素p相除得到的余数来分析题目; - 若
reminder为0,则证明能被目标元素整除,则不需要移除子数组,返回0即可; - 若
reminder不为0,则需要寻找如何移除子数组才可以整除; - 记
sum1 = a + b + c,sum2 = a + b + c + d,若sum1 % p === sum2 % p,那么(sum1 - sum2) % p = 0,也就是sum2中移除sum1后可以整除; - 按照步骤4的推论,可以得知,若
sumi % p === (sumj - reminder) % p则说明(i,j]中存在移除某个子数组后能被p整除的子数组,因此遍历数组寻找最小的子数组返回其长度即可。
AC 代码
/**
* @param {number[]} nums
* @param {number} p
* @return {number}
*/
var minSubarray = function(nums, p) {
const len = nums.length
let sum = 0
for(let i = 0; i < len; i++) {
sum += nums[i]
}
const reminder = sum % p
if(reminder === 0) {
return 0
}
const map = new Map
let currentSum = 0
let res = Infinity
map.set(0, -1)
for(let i = 0; i < len; i++) {
currentSum += nums[i]
const key = (currentSum - reminder + p) % p
if(map.has(key)) {
res = Math.min(res, i - map.get(key))
if( res === 1 && len > 1 ){
return res
}
}
map.set(currentSum % p, i)
}
if(res >= len) res = Infinity
return res === Infinity ? -1 : res
};
结果:
- 执行结果: 通过
- 执行用时:100 ms, 在所有 JavaScript 提交中击败了96.00%的用户
- 内存消耗:60.1 MB, 在所有 JavaScript 提交中击败了96.00%的用户
- 通过测试用例:142 / 142