数据结构:连续子数组的最大和(附头条面试题)

Posted 咕泡研习社

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构:连续子数组的最大和(附头条面试题)相关的知识,希望对你有一定的参考价值。


题目描述

一维数组中元素有正有负,求连续子向量的最大和。例如数组arr = {6,-3,-2,7,-15,1,2,2},连续最大子向量和为8(从下标0开始下标3结束)。

分析

暴力解法

最直观的方法,暴力遍历,将所有可能的子集遍历一遍。
但是存在的子数组有n(n+1)/2个,遍历一遍的时间复杂度为o(n^2),对于大数据量肯定不行。

一般解法

我们从头到尾将数组元素一个个往前加。
定义两个变量int maxNum = 0当前最大和、int currSum = 0累加数组的和,然后开始遍历累加:
当累加数组的和currSum小于0时,则抛弃之前的和将当前数组元素赋值给currSum(因为假如之前的和为负数,那肯定拖累后面的和,不抛弃重头开始算肯定不可能是最大值,我们算的是连续子向量的最大和), 前最大和maxNum数值不变(第一步即数组下标0时maxNum=currSum)
当累加数组的和currSum大于0时,则将当前元素值累加到currSum,并currSum与maxNum进行比较
当currSum大于maxNum,则将maxNum=currSum;
当currSum小于maxNum,则maxNum不变
时间复杂度为O(n)
操作过程如下({6,-3,-2,7,-15,1,2,2}):

数据结构:连续子数组的最大和(附头条面试题)


示例代码如下:

package com.example.demo;
public class Test5 {
public static void main(String[] args) { int[] arr = new int[]{6,-3,-2,7,-15,1,2,2}; System.out.println(getMax( arr)); }
public static int getMax(int[] arr){if(null == arr || arr.length <= 0){ return 0; } int maxNum= arr[0]; int currSum = arr[0]; for(int i = 1; i<arr.length; i++){ if(currSum > 0){ currSum += arr[i]; }else{ currSum = arr[i]; } if(currSum > maxNum){ maxNum = currSum; } } return maxNum; }}

动态规划,其实跟上面是一样的

区别就在于每一步计算的累加的子数组和currSum用一个新的currSumArr数组保存了,每一次让currSumArr[i-1]来比较,跟上面是一模一样的。
算法公式为:
 
   
   
 
max( dp[ i ] ) = getMax( max( dp[ i -1 ] ) + arr[ i ] ,arr[ i ] )
示例代码:
package com.example.demo;
public class Test6 {
public static void main(String[] args) { int[] arr = new int[]{6,-3,-2,7,-15,1,2,2}; System.out.println(getMax( arr)); }
public static int getMax(int[] arr){ if(null == arr || arr.length <= 0){ return 0; } int maxNum= arr[0]; int[] currSumArr = new int[arr.length]; currSumArr[0] = arr[0]; for(int i = 1; i<arr.length; i++){ if(currSumArr[i-1] > 0){ currSumArr[i] = currSumArr[i-1] + arr[i]; }else{ currSumArr[i] = arr[i]; } if(currSumArr[i] > maxNum){ maxNum = currSumArr[i]; } } return maxNum; }}

扩展

头条面试问题

100w用户,计算最大在线人数和时间段,已知用户的登陆时间和登出时间
例如:
2019-07-08 12:30:00 - 2019-07-08 13:30:00
2019-07-08 12:00:00 - 2019-07-08 14:30:00
2019-07-08 12:10:00 - 2019-07-08 14:10:00
……

路:


其实上面的问题还是求连续子数组最大和问题(时间是连续线性的)
按计算当天为例(是计算一天还是一月只是单位不同,方法一样)
定义个长度为86400长度的整数数组(一天有这么多秒)用来存储每一秒用户变化登陆+1 登出-1,初始人数为0
则将数据初始入数组后,按公式max( dp[ i ] ) = getMax( max( dp[ i -1 ] ) + arr[ i ] ,arr[ i ] )便可求出当天最大在线人数是多少。
至于最大在线人数所在的时间段,其实就是该子数组的下标区间,修改一下dp数组的结构,记录一下每个和的子数组下标区间就可以了,例如dp结构改为:
dp[[当前子数组最大和,子数组最小下标,子数组最大下标]]
时间复杂度为o(n)

链接:https://gper.club/articles/7e7e7f7ff4g59gc7g6d

推荐阅读:


升职加薪 就来咕泡学院

欢迎加入研习社专属福利群

享受福利第一时间送达的特权

长按二维码加入


小贴士
多看
多分享
多“在看”
会有福利宠幸你~


以上是关于数据结构:连续子数组的最大和(附头条面试题)的主要内容,如果未能解决你的问题,请参考以下文章

[剑指offer]面试题31:连续子数组的最大和

剑指offer面试题 42. 连续子数组的最大和

剑指offer面试题42. 连续子数组的最大和

剑指offer面试题42. 连续子数组的最大和

面试题31 连续子数组的最大和

剑指OFFER----面试题42. 连续子数组的最大和