面试官在“逗”你系列:连续子数组的最大和或最小和

胡哥有话说
• 阅读 1528

前言

本文题目是“连续子数组的最大和或最小和”。

话不多说,开始“打怪”修炼...

一、理解题目

以“连续子数组的最大和”为例,相当于我们在数组中,计算连续的子数组的和,找寻最大值。如在数组[3, -2, 1, 2, 4, -6, 5]中连续子数组的最大和为:3 + (-2) + 1 + 2 + 4 = 8

输入:[3, -2, 1, 2, 4, -6, 5]
输出:8

一定要准确的理解题意,如不是特别明确,建议与面试官再次沟通确认,避免需求与实现不一致的情况。

二、解决方案

连续子数组的最大和

这道面试题有几种解决方案呢?可能在很多个同学的脑海里会出现这样的一种方案:

1. 求连续子数组组合方案:

将数组中的元素进行连续子数组的组合,每一种组合计算出一个值,依次比较后取出最大值。那这种方式是可以肯定是可以最终的效果的,But这么处理的话,会有多少种组合方案呢?

以数组 [1, -1, 2, -3, 5]为例:
    连续子数组有:N + (N-1) + (N-2)...  +  1 = n*(n+1) / 2

随着数组长度N的值越大,组合数量肯定是越大!同时在获取阶乘后,还需要再次进行一次最大值得比较。

划重点:

此方案虽可以实现最终的效果,但是确实十分不可取的!

2. 最优解方案

在面试时面试题除了固定的套路和算法外,要多尝试逻辑思维的转变...

技术方案:
    1. 初始化两个变量:sum(连续子数组的累加和)、max(最大值)
    2. 遍历数组元素,考虑sum的情况: 
        sum >= 0,将当前元素的值进行累加
        sum < 0,注意,sum的值为负值,不管当前的元素值是什么,累加sum(负数)肯定值最终会变小的,所以此刻,要重新对sum进行赋值操作
    3. 每次遍历时,都要比较sum和max的大小, 如果 sum > max,进行赋值max = sum
    4. 返回最终的结果max

接下来,我们来看下代码的实现:

/**
 * getGreatestSumOfSubArray()
 * @description 获取连续子数组中最大和
 * @param Array arr 指定的数组
 * @returns Number sum 最大和
*/
function getGreatestSumOfSubArray (arr) {
  // 容错边界处理
  if (!Array.isArray(arr) || arr.length === 0) {
    return 0
  }

  // 解构,初始获取数组的第一个元素值
  // 注意:一定不能把sum和max设置初始化为0,必须要考虑数组元素中全部为负数的情况
  let [ sum ] = arr
  let [ max ] = arr

  let len = arr.length
  for (let i = 1; i < len; i++) {
    // 如果当前sum累加 < 0,重新初始化当前元素值;否则执行累加
    if (sum < 0) {
      sum = arr[i]
    } else {
      sum += arr[i]
    }

    // 比较累加和与最大值
    if (sum > max) {
      max = sum
    }
  }

  return max
}

// 调用
let max = getGreatestSumOfSubArray([3, -2, 1, 2, 4, -6, 5])
console.log(max) // 8

OK,这样我们就实现了需求,小朋友,你还有问号吗?

连续子数组的最小和

“连续子数组的最小和” 这个需求的实现原理和“连续子数组的最大和”的实现基本是一致的,唯一的区别点为:当sum的值 > 0为正数时,累加就无意义了,需要重新赋值为当前值。我们来看下代码的实现

/**
 * getLeastSumOfSubArray()
 * @description 获取连续子数组的最小和
 * @param Array arr 指定的数组
 * @returns Number min 最小和
*/
function getLeastSumOfSubArray (arr) {
  if (!Array.isArray(arr) || arr.length === 0) {
    return 0
  }

  // 初始化
  let [ sum ] = arr
  let [ min ] = arr

  // 遍历数组元素,如果sum是一个正数,累加就无意义,重新赋值为当前项;
  let len = arr.length
  for (let i = 1; i < len; i++) {
    if (sum > 0) {
      sum = arr[i]
    } else {
      sum += arr[i]
    }
    if (sum < min) {
      min = sum
    }
  }

  return min
}

let min = getLeastSumOfSubArray([-1, -2, 3, 2, -4, -8])
console.log(min) // -12 = (-4) + (-8)

这个了解了不...

后记

以上就是胡哥今天给大家分享的内容,喜欢的小伙伴记得点赞收藏呀,关注胡哥有话说,学习前端不迷路,欢迎多多留言交流...

胡哥有话说,专注于大前端技术领域,分享前端系统架构,框架实现原理,最新最高效的技术实践!

点赞
收藏
评论区
推荐文章
孤心独饮 孤心独饮
3年前
从零开始刷力扣(一)——485:最大连续1的个数
分类:数组的遍历题目描述:给定一个二进制数组,计算其中最大连续1的个数。示例1:输入:1,1,0,1,1,1输出:3解释:开头的两位和最后的三位都是连续1,所以最大连续1的个数是3.思路初始化count和maxCount,然后遍历数组,遇见1则count,并且更新与maxCount比较,若比maxCount更大,则更新m
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Chase620 Chase620
3年前
ArrayList底层
一、ArrayList集合底层数据结构1.ArrayList集合介绍List集合的可调整大小数组实现。2.数组结构介绍增删快:每次增加删除元素,都需要更改数组长度、拷贝以及移除元素位置。查询快:由于数组在内存中是一块连续空间,因此可以根据地址索引的方式快速获
似梦清欢 似梦清欢
1年前
排序算法(冒泡、快速、插入)
稳定性:排序前后相等的元素位置是否会被交换。冒泡排序strcpy只能拷贝字符串,整型或浮点型数组需要用memcpy。memcpy称为内存拷贝接口,可以将某一段连续的内存放入另一段连续的内存中。在使用随机数的代码中使用固定的数组有利于调试。:::tipmem
Wesley13 Wesley13
3年前
Java开发者容易犯的十个错误
!(https://oscimg.oschina.net/oscnet/c9f00cc918684fbe8a865119d104090b.gif)Top1.数组转换为数组列表将数组转换为数组列表,开发者经常会这样做:\java\List<StringlistArrays.asList(arr);Arr
Stella981 Stella981
3年前
Javascript获取数组中最大和最小值方法
1.使用Math中的max/min方法vararr22,13,6,55,30;varmaxMath.max.apply(null,arr);varminMath.min.apply(null,arr);console.log(max,min)//5
Stella981 Stella981
3年前
LeetCode 5561. 获取生成数组中的最大值
文章目录1\.题目2\.解题1\.题目给你一个整数n。按下述规则生成一个长度为n1的数组nums:nums00nums11当2<2i<n时,nums2inumsi
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
达里尔 达里尔
11个月前
给数组添加新数据,判断数据是否重复
多选要进行数组拼接,希望判断往原数组里添的新数据是否重复,封装个简易方法languageconstdataArrayname:'aaa',id:1,name:'bbb',id:2;constnewDataname:'ccc',id:2;//要添加的新数
小万哥 小万哥
3个月前
Kotlin 循环与函数详解:高效编程指南
Kotlin中的循环结构让你能轻松遍历数组或范围内的元素。使用for循环结合in操作符,可以简洁地访问数组中的每个项,如字符串数组或整数数组。对于范围,可以用..来定义一系列连续的值并进行迭代。此外,Kotlin支持通过break和continue控制循环流程。函数则允许封装可复用的代码块,你可以定义接受参数并返回值的函数,利用简写语法使代码更加紧凑。例如,myFunction(x:Int,y:Int)xy简洁地定义了一个计算两数之和的函数。