网易笔试 被6整除的最大子项和 JS

网易笔试 被6整除的最大子项和 JS

最近一次的网易前端笔试里有一题,题目大意是这样的:

求数组中最大的子项和,使得该子项和能被6整除,如果没有则返回-1

 
 

题目分析

要求数组能被6整除的最大子项和,相当于计算数组总和后对6取余得到总和余数,然后数组中对6取余恰好为总和余数的一项或多项组合去掉。

 
 

如果数组其中一项的余数恰好为总和余数,那直接把这一项剔除即可。

例如,数组[5,7,9],总和为
5 + 7 + 9 = 21 5+7+9=21 5+7+9=21
21对6取余后得到余数为3,那么找到数组中对6取余为3的那一项剔除即可。对数组每一项对6取余得到

数组元素579
对6取余结果513

因此只要把9剔除,剩下的就是6的倍数。

 
 
 
 
 
 

但假如所有项的余数都恰好不是总和余数,则需要将这些元素进行组合,尝试产生新的余数,直至找到总和余数。

例如,数组[2,3,4,8],总和为
2 + 3 + 4 + 8 = 17 2+3+4+8=17 2+3+4+8=17
17对6取余后得到余数为5,对数组每一项对6取余得到

数组元素2348
对6取余结果2342

发现数组中并没有直接使得余数为5的项,此时单独剔除一项已经无法满足要求,但如果是多项组合,能否得到想要的余数呢?
 

对已有余数的项进行组合,尝试得到新余数。

数组元素组合2+3=52+4=63+4=7
对6取余结果501

此时可以得到总和余数5,因此只需把2和3两个剔除即可得到结果。

注意:如果数组中多项取得相同余数,那么只需取最小项进行组合,因为题目要求是求最大的子项和,有重复的选项选取最小的剔除即可。

 
 
 
 
 
 

那么,怎么找数组元素的组合,使得组合的余数为想要的结果呢?

从最小的元素遍历查找,并用一个余数数组来存放已经能获取到的余数的对应值,数组下标为余数,内容为算得该余数的元素。

遍历每个元素时,用当前元素与已有的余数进行组合,如果产生新的余数,则放到对应的位置,如果位置上有值了,则说明还有更小的方案能得到相应的余数,就不用再管。
 
 

[2,3,4,8],遍历时,首先得到2这一项,因为余数数组是空的,则直接放入即可

余数12345
对应元素null 2 nullnullnull

到3这一项时,将3与余数数组中已有的2的一项组合,产生新的余数5,放入数组;3自身也是一个新的余数,同样放入数组

余数12345
对应元素null 2  3 null2+3

此时已经得到结果项。如果还未得到结果,则继续遍历。所有元素组合都得不到想要的结果时,则返回-1。
 
 
 
 
 
 

步骤

  1. 遍历整个数组,计算总和和余数,并把能被6整除的元素剔除
  2. 对数组进行排序
  3. 遍历数组,计算每项对6取余的结果,以及与其他项组合后对6取余的结果
  4. 用余数数组存放已有的余数结果,用于后续计算
  5. 重复3,4步骤,直至找到想要的余数结果

 
 
 
 
 
 

JS实现

function calc6(arr) {
  let sum = 0, i = 0

  // 计算总和,并剔除被6整除的项
  while (i < arr.length) {
    sum += arr[i]
    if (arr[i] % 6 == 0) {
      arr.splice(i, 1)
    } else {
      i++
    }
  }

  // 计算和对6的余数
  let sumRemain = sum % 6
  if (sumRemain == 0) return sum

  // 暂存可以能得到对应余数的最小结果
  const remainArray = Array(6)

  // 对arr排序,从最小开始寻找各个余数
  arr.sort((a, b) => a - b)

  i = -1
  while (++i < arr.length) {
    // 计算当前项的余数
    let remain = arr[i] % 6
    if (remain == sumRemain) return sum - arr[i]

    // 存放当前项能组成的各种结果
    let temp = [arr[i]]

    // 与之前的余数结果进行组合
    for (let i in remainArray) {
      if (remainArray[i]) {
        // 如果该项存在,则和当前项组合,获得新的组合结果
        temp.push(remainArray[i] + arr[i])
      }
    }

    // 遍历当前项组成的所有结果
    for (let num of temp) {
      // 计算每项的余数
      let newRemain = num % 6
      if (newRemain == sumRemain) return sum - num

      // 如果不存在,则说明组合产生了新的余数,并放到对应位置
      if (!remainArray[newRemain]) remainArray[newRemain] = num
    }
  }
  return -1
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值