哈希妙用—最长子数组问题

版权声明:本文为博主原创文章,未经博主允许不得转载,博客地址: https://blog.csdn.net/qq_31601743/article/details/89816501

前言

有关哈希的基础知识,详见我上一篇“什么是哈希”的文章。

问题描述

给定一个数组arr,和一个整数num,求在arr中,累加和等于num的最长子数组的长度

例子:arr = {7,3,2,1,1,7,7,7} num = 7 其中有很多的子数组累加和等于7,但是最长的子数组是{3,2,1,1},所 以返回其长度4。

问题分析

第一种方法:暴力求解

这种方法很容易想到,但其时间复杂度为O(n²)。

为方便起见,假设数组arr={7,3,2,2,1},num=7.

从第一个数7开始,分别从前往后进行1个数、2个数、3个数.....的相加,加到最后一个数。然后从第二个数3开始,重复上述步骤,遍历所有情况,返回那个最长的长度。

遍历第一个数7

遍历第二个数3

此时发现有个加和等于7,即3+2+1+1=7,记录此时长度,为4,然后,再遍历下一个数2,再进行上述操作,直到所有情况遍历完毕。该算法的时间复杂度为O(n²),下面使用哈希表来是该问题的时间复杂度变为O(n)

第二种方法:使用哈希表

举个例子,arr={6,3,2,1,1},num=7。考虑这样一种情况,遍历该数组arr,每遍历到一个位置的时候,把该位置的数和前面的数先累加起来得到sum,然后减去num,看它前面的累加是否有出现过sum-num的值,如果出现,那么后面的这一块必定是等于num,长度即为当前遍历的位置减去前面累加和的最后一个位置。如图。

当遍历到arr[4]的时候,得到的sum=6+3+2+1=13,减去num,即减去7,得到6,看看前面是否有累加和为6的值。

一、发现有,则后面这一块的值必定为num,即为7,该子数组的长度为当前遍历位置减去前面累加和的最后一个位置,即6的位置。

二、若减去7得到一个结果并没有在前面的累加和出现过的话,则不更新最大长度。

三、把累加结果保存到哈希表

累加和可以使用哈希表来进行存储,查找和保存的结果都为O(1)的操作。可以知道,只需把数组遍历一遍即可得出答案,时间复杂度为O(N).

算法遍历到arr[4]时,哈希表如图。

代码

public static int maxLength(int[] arr, int k) {
 if (arr == null || arr.length == 0) {
 return 0;
 }
 HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
 map.put(0, -1); // important
 int len = 0;
 int sum = 0;
 for (int i = 0; i < arr.length; i++) {
 sum += arr[i];
 if (map.containsKey(sum - k)) {
 len = Math.max(i - map.get(sum - k), len);
 }
 if (!map.containsKey(sum)) {
 map.put(sum, i);
 }
 }
 return len;
 }

更多干货,请扫码关注“IT界的泥石流微信公众号哦,带你领略编程之美!

猜你喜欢

转载自blog.csdn.net/qq_31601743/article/details/89816501