【Leetcode】1590. Make Sum Divisible by P

题目地址:

https://leetcode.com/problems/make-sum-divisible-by-p/

给定一个长 n n n正整数数组 A A A,再给定一个正整数 p p p,可以将 A A A中删除一个子数组(可以是空),使得剩下的数之和被 p p p整除。问要删除的子数组的长度最短可以是多少。

先求一下 A A A的和 s s s,设 s ≡ x ( m o d    p ) s\equiv x(\mod p) sx(modp)并且 0 ≤ x < p 0\le x<p 0x<p,若 x = 0 x=0 x=0则直接返回 0 0 0,否则这个问题等价于问 A A A最短的模 p p p x x x的子数组长度是多少。先求一下 A A A的前缀和模 p p p的数组 c c c,这里 c [ i ] = ( ∑ k = 0 i − 1 A [ k ] ) m o d    p c[i]=(\sum_{k=0}^{i-1}A[k])\mod p c[i]=(k=0i1A[k])modp,然后遍历 c c c,并且开一个哈希表存遍历到当前位置之前,前缀和模 p p p的值与其在 c c c里最后出现的下标,如果当前前缀和模 p p p u u u,并且哈希表里存在某个等于 v v v的key,使得 u − v ≡ x ( m o d    p ) u-v\equiv x(\mod p) uvx(modp),那么就找到了以当前位置为右端点的和模 p p p等于 x x x的最短子数组,则可以更新答案。代码如下:

import java.util.HashMap;
import java.util.Map;

public class Solution {
    
    
    public int minSubarray(int[] nums, int p) {
    
    
        int n = nums.length;
        if (n == 0) {
    
    
            return 0;
        }
        
        // 求一下总和模p是多少
        int sum = 0;
        for (int num : nums) {
    
    
            sum = (sum + num) % p;
        }
        
        // 如果总和模p为0,则不用删除任何子数组,返回0
        if (sum == 0) {
    
    
            return 0;
        }
        
        int res = n;
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, 0);
        // 为了节省空间,就不开前缀和数组了,由preSum变量代替
        for (int i = 0, preSum = 0; i < n; i++) {
    
    
            preSum = (preSum + nums[i]) % p;
            
            int key = (preSum - sum + p) % p;
            if (map.containsKey(key)) {
    
    
                int l = map.get(key);
                res = Math.min(res, i + 1 - l);
            }
            
            map.put(preSum, i + 1);
        }
        
        return res == n ? -1 : res;
    }
}

时空复杂度 O ( n ) O(n) O(n)

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/112761042