利用Java实现和可被K整除的子数组完整实例

 更新时间:2024年01月23日 11:17:52   作者:楠枬  
这篇文章主要给大家介绍了关于利用Java实现和可被K整除的子数组的相关资料,这道题来自力扣,通过学习这道题的解题思路以及代码对大家的学习或者工作具有一定的参考借鉴价值,需要的朋友可以参考下

一、题目描述

给定一个整数数组 nums 和一个整数 k ,返回其中元素之和可被 k 整除的(连续、非空) 子数组 的数目。

子数组 是数组的 连续 部分。

示例:

输入:nums = [4,5,0,-2,-3,1],k = 5

输出:7

输入:nums = [ 5 ],k = 9

输出:0

二、题解

思路分析

首先我们很容易想到暴力枚举的方法,即遍历数组,在遍历每个元素的同时向后寻找元素之和能够被k整除的子数组

暴力枚举代码如下:

class Solution {
    public int subarraysDivByK(int[] nums, int k) {
       int ret = 0;
       for(int i = 0; i < nums.length; i++){
           int sum = 0;
           for(int j = i; j < nums.length; j++){
               sum += nums[j];
               if(sum % k == 0){
                   ret++;
               }
           }
       }
       return ret;
    }
}

其时间复杂度为O(N^{2}),当输入的nums数组较大时,会超出时间限制,因此,暴力枚举方式行不通,我们继续考虑其他方法

题目中要求我们找到元素之和可被k整除的(连续、非空)子数组,因此我们可以想到使用双指针的思路,即考虑使用滑动窗口来解决这个问题,然而,本题不能使用滑动窗口来解决

为什么不能使用滑动窗口?

参照示例1,其输入的数组 nums = [4,5,0,-2,-3,1],其中不仅有正整数,还有零和负数,

在使用滑动窗口时,当窗口内元素满足条件时,要移动left指针,向前滑动窗口,但在本题中,由于有零和负整数,在窗口内元素满足条件时,不能移动left指针,因为下一个元素可能是零,加入后任满足条件,也可能几个元素相加等于0,加入后也满足条件。因此,若是使用滑动窗口来解决本题,则会漏掉一些符合情况的子数组。

滑动窗口的思路也不行,我们继续思考新的方法,在涉及子数组问题时,我们也常使用前缀和来解决问题

什么是前缀和?

前缀和即某序列的前n项和,类似于数学中的数列前n项和。即从首元素位置到i位置这个区间内所有元素之和,前缀和只是一种思路,其不仅可以求和,也可以求从首元素位置到i位置区间内的乘积等等。

我们以示例1为例子,先求前缀和数组,再通过前缀和数组来求解子数组,

然而,在这种情况下,当我们求解子数组时,仍然需要后遍历,求得从i到j位置的元素之和,再判断其是否符合条件,

其时间复杂度仍是O(N^{2}

在通过前缀和数组求解子数组时,我们可以考虑向前遍历,即i位置上的元素为到i位置的元素之和

N^{2}

此时,若以i位置为结尾的区间内的元素能够被被k整除,则

 此时dp[i] - dp[j] = mk,(m为系数),即dp[i]与dp[j]同余(dp[i]取余 k 与dp[j]取余 k 的余数相同)(两数余数相同,在相减时就将余数消去,剩下的数便能整除k),此时,我们只需要找到,在i位置之前有多少个前缀和元素的余数与其前缀和相同,就能够得到以i位置为结尾的且能够被k整除的子数组个数。

然而,在求i位置之前有多少个前缀和元素的余数与其相同时,我们还需要再向前遍历一遍前缀和数组吗?

我们可以使用哈希表,存储前缀和元素的余数及其个数,这样,便只需要计算dp[i]的余数,再从哈希表中找到相同余数的元素个数,就可知道以i位置为结尾的且能够被k整除的子数组个数了。

在分析完思路后,我们来考虑其具体实现过程:

具体实现

首先我们需要一个哈希表,以前缀和元素模k的值为键,值的个数为值

// key:模k的的值,value:key的个数
Map&lt;Integer, Integer&gt; hash = new HashMap&lt;&gt;();

需要注意的是,在模k时,如果元素为负数,求出的值也为负数(例如 -4 % 5 = -4,-4 与 1 是同余的,若我们在哈希表中保存(-4, 1),而 % i的结果为 1,并在哈希表中找到结果为1的元素个数,此时就漏掉了结果 为 -4 的情况),

因此我们需要对其进行处理,将其变为正数,可以将其+k,使其变成正数,即 dp[i] % k + k(-4 + 5 = 1);当其为正数的时候则不需要 +k,若想要无需对元素进行正负数判断,则可在 +k 后再取余k,即 (dp[i] % k + k) % k,此时,若元素为正数,在 +k 后结果大于k,再对结果进行取余,又将其变为正确结果((3 % 5 + 5)% 5);若元素为负数,在 +k 后将负数变为正数,即正确结果,再对结果进行取余,仍是正确结果((-4 % 5 + 5)% 5)

求出数组的前缀和数组

由于哈希表中保存的是模k的值及其个数,因此我们不需要再创建一个前缀和数组用来保存前缀和,只需使用变量sum 来保存前i-1个元素的和

何时将结果放到哈希表中?

我们要从哈希表中找到相同余数的元素个数,从而知道以i位置为结尾的且能够被k整除的子数组个数,因此哈希表中不能存放i位置之后的元素结果,因此,每遍历一个元素,就将其结果更新到哈希表中

然而,此时还有一个细节问题

若以i位置为结尾的数组本身便能被k整除,此时模k的结果为 0,即从0位置到i位置的子数组之和能够被k整除,则在第一次出现该情况时,哈希表内没有key = 0的元素,会漏掉该结果,因此,我们需要处理这种特殊情况,即手动将(0, 1)放入哈希表中

完整代码

class Solution {
    public int subarraysDivByK(int[] nums, int k) {
        // key:模k的的值,value:key的个数
       Map<Integer, Integer> hash = new HashMap<>();
       //处理特殊情况
        hash.put(0,1);
        int ret = 0;//子数组的个数
        int sum = 0;//用来保存前i-1个元素之和
        for(int i = 0; i < nums.length; i++){
            sum += nums[i];
            //求出与 前i个元素之和 同余的元素个数
            int same = hash.getOrDefault((sum % k + k) % k, 0);
            ret += same;//更新结果
            hash.put((sum % k + k) % k,same + 1);//更新哈希表
        }
        return ret;
    }
}

题目来自:

974. 和可被 K 整除的子数组 - 力扣(LeetCode)

总结

到此这篇关于利用Java实现和可被K整除的子数组的文章就介绍到这了,更多相关Java和可被K整除的子数组内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • vue+springboot项目上传部署tomcat的方法实现

    vue+springboot项目上传部署tomcat的方法实现

    本文主要介绍了vue+springboot项目上传部署tomcat的方法实现,包括环境准备、配置调整以及部署步骤,文中通过图文及示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-01-01
  • 一篇文章带你了解JavaSE的数据类型

    一篇文章带你了解JavaSE的数据类型

    这篇文章主要给大家介绍了关于JavaSE的数据类型,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2021-09-09
  • Java中Switch用法代码示例

    Java中Switch用法代码示例

    这篇文章主要介绍了Java中Switch用法代码示例,向大家分享了两段代码,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • Springboot创建子父工程过程图解

    Springboot创建子父工程过程图解

    这篇文章主要介绍了Springboot创建子父工程过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • 解决Jackson解析嵌套类问题(MismatchedInputException)

    解决Jackson解析嵌套类问题(MismatchedInputException)

    这篇文章主要介绍了解决Jackson解析嵌套类问题(MismatchedInputException),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • java 泛型的详解及实例

    java 泛型的详解及实例

    这篇文章主要介绍了java 泛型的详解及实例的相关资料,希望通过本文大家能彻底掌握泛型的使用方法,需要的朋友可以参考下
    2017-08-08
  • java eclipse 中文件的上传和下载示例解析

    java eclipse 中文件的上传和下载示例解析

    这篇文章主要介绍了eclipse java中文件的上传和下载示例解析,文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的。对此感兴趣的小伙伴可以了解一下
    2020-07-07
  • Spring Boot详解各类请求和响应的处理方法

    Spring Boot详解各类请求和响应的处理方法

    平时只是在用SpringBoot框架,但并没有详细研究过请求和响应执行的一个具体过程,所以本文主要来梳理一下SpringBoot请求和响应的处理过程
    2022-07-07
  • java二分查找插入法

    java二分查找插入法

    当你需要构建一个大的有序队列,用插入发太慢了,可以先用二分查找法,找到在队列要插入的位置,把数后移一下,然后放进去。比较效率,下面是java使用示例,需要的朋友可以参考下
    2014-03-03
  • Maven实战之搭建Maven私服和镜像的方法(图文)

    Maven实战之搭建Maven私服和镜像的方法(图文)

    本篇文章主要介绍了搭建Maven私服和镜像的方法(图文),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12

最新评论