JavaInterview JavaInterview
首页
指南
分类
标签
归档
  • CSDN (opens new window)
  • 文档集合 (opens new window)
  • 系统架构 (opens new window)
  • 微信号 (opens new window)
  • 公众号 (opens new window)

『Java面试+Java学习』
首页
指南
分类
标签
归档
  • CSDN (opens new window)
  • 文档集合 (opens new window)
  • 系统架构 (opens new window)
  • 微信号 (opens new window)
  • 公众号 (opens new window)
  • 指南
  • 简历

  • Java

  • 面试

  • 算法

  • algorithm
  • leetcode
JavaInterview.cn
2025-05-10
目录

使数组和能被P整除Java

文章发布较早,内容可能过时,阅读注意甄别。

# 题目

给你一个正整数数组 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

# 思路

定义前缀和数组

# 解法

class Solution {
    public int minSubarray(int[] nums, int p) {
        // 思路:使用前缀和 s[] (s[0] = 0[表示前0 个元素])的方法
        // 首先得到数组和,对 p 进行取余,查看余数 x;
        // 如果 x = 0,那就更好,直接返回 0;
        // 如果 x ≠ 0,那么就要去掉一连串元素,使得 x = 0
            // 这里面的一连串元素刚好是(某两个前缀和之差)
            // 思想就是,两个前缀和之差的对 p 进行取余,等于 x, 那么刚好去除他们,得到 x = 0,满足题意
        // 综上,(s[right] - s[left]) % p = x, 即 s[right] − s[left] ≡ x (mod p)
        // s[right] - x = s[left] (mod p)
        // 为了保证左项不为负数,等价于下面的式子:
        // ((s[right] - x) % p + p) % p = s[left] % p (***)
        // 题目转化就是找到这个 right 和 left,且 right - left 最小, 按照如上式求解

        int len = nums.length;
        // 定义前缀和数组
        int [] s = new int[len + 1];
        for(int i = 1; i <= len; i++){
            s[i] = (s[i - 1] + nums[i - 1]) % p;
        }
        // 找到数组和的取余数
        int x = s[len];
        // 等于 0 就直接返回
        if(x == 0){
            return 0;
        }
        // 最大返回 n 次
        int ans = len;
        // 使用 hashMap 来存,方便查找符合条件的
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        // 根据(***) 求解
        for(int i = 0; i <= len; i++){
            // s[right]
            map.put(s[i], i);
            // 找已存入的,即 s[left]
            //  不存在就返回 - len, 那么 i - j >= n
            int j = map.getOrDefault((s[i] - x + p) % p, -len);
            ans = Math.min(ans, i - j);
        }
        // 因为不能全部删除,所以肯定是小于 n
        return ans < len ? ans: -1;


    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# 总结

  • 分析出几种情况,然后分别对各个情况实现
微信 支付宝
#Java
最近更新
01
1633. 各赛事的用户注册率 Java
07-13
02
1636. 按照频率将数组升序排序 Java
07-13
03
1640. 能否连接形成数组 Java
07-13
更多文章>
Theme by Vdoing | Copyright © 2019-2025 JavaInterview.cn
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式