1589 使数组和能被 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

方法1:
主要思路:
(1)使用类似前缀和的思路,保存前面的出现的和的余数,当后面再次出现时,说明中间这段子数组满足一定的要求;
(2)该题的主要变化点是如何定义中间这段要处理的子数组,既作为要去除的部分数组,使整个数组的剩余部分能够整除p,则对中间这段要去除的子数组的和,就要求能够在加上部分值之和可以整除p

class Solution {
public:
    int minSubarray(vector<int>& nums, int p) {
    	//p等于1时,直接返回0
        if (p == 1) {
		    return 0;
	    }
		//计算总和
	    long long sum_all = 0;
	    for (int i = 0; i < nums.size(); ++i) {
		    sum_all += nums[i];
	    }
	    //若总和可以整除 p,则直接返回0
	    if (sum_all%p == 0) {
		    return 0;
	    }
	    //若总和小于p,则返回-1
	    if (sum_all < p) {
		    return -1;
	    }
	    //找出余数,中间的子数组加上该余数后,若是能够整除p,则说明剩余的数组元素和可以整除p
	    int leave =p-sum_all % p;
		//保存前缀和的余数
	    unordered_map<long long, int>mp;
	    mp[0] = -1;//初始值
	    long long cur_sum = 0;//前面元素的和
	    int len = INT_MAX;//要去除的最短的子数组的长度
	    for (int i = 0; i < nums.size(); ++i) {
		    cur_sum += nums[i];//和
		    //满足要去除的子数组的条件
		    if (mp.count((cur_sum + leave) %p)) {
			    len =min(len, i - mp[(cur_sum + leave) % p]);
		    }
		    //将当前余数的对应的索引更新,若是之前出现过该余数,就替换成了更大的索引值,来求取更小的子数组长度
		    mp[cur_sum  % p] = i;
	    }
		//返回结果
	    return len>=nums.size()?-1:len;
    }
};
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页