本文涉及的基础知识点
C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频
质数、最大公约数、菲蜀定理
LeetCode 1590. 使数组和能被 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 <= 105
1 <= nums[i] <= 109
1 <= p <= 109
前缀和
N = nums.size()
由于是对p求余,所以求前缀和的时候直接对p求余。
如果nums的和能被p整除则返回0。否则令p1 = sum(num)%p ;
假定nums[i…j]被删除,枚举j。令preSum[j+1]为p2。则在preSum[0…j]中求值为 (p1-p2+p)%p 的下标i,如果有多个符合的下标取最大下标。ret = j-i+1的最小值,如果ret == n,返回-1,否则返回ret。
mValueIndex 的key:preSum[i]的值,value:i。
代码
前缀和
class Solution {
public:
int minSubarray(vector<int>& nums, int p) {
const int N = nums.size();
vector<int> preSum(1);
for (const auto& n : nums) {
preSum.emplace_back((n + preSum.back()) % p);
}
const int p1 = preSum.back() % p;
if (0 == p1) { return 0; }
unordered_map<int, int> mValueIndex;
int ret = N;
for (int j = 0; j < N; j++) {
mValueIndex[preSum[j]] = j;
const int p3 = (preSum[j + 1] - p1 + p) % p;
if (mValueIndex.count(p3)) {
ret = min(ret, j + 1 - mValueIndex[p3]);
}
}
return (N == ret) ? -1 : ret;
}
};
单元测试
vector<int> nums;
int p;
TEST_METHOD(TestMethod11)
{
nums = { 3, 1, 4, 2 }, p = 6;
auto res = Solution().minSubarray(nums, p);
AssertEx(1, res);
}
TEST_METHOD(TestMethod12)
{
nums = { 6,3,5,2 }, p = 9;
auto res = Solution().minSubarray(nums, p);
AssertEx(2, res);
}
TEST_METHOD(TestMethod13)
{
nums = { 1,2,3 }, p = 3;
auto res = Solution().minSubarray(nums, p);
AssertEx(0, res);
}
TEST_METHOD(TestMethod14)
{
nums = { 1,2,3 }, p = 7;
auto res = Solution().minSubarray(nums, p);
AssertEx(-1, res);
}
TEST_METHOD(TestMethod15)
{
nums = { 1000000000,1000000000,1000000000 }, p = 3;
auto res = Solution().minSubarray(nums, p);
AssertEx(0, res);
}