具有适当总和的数组元素的序列计数

时间:2016-10-18 20:43:54

标签: arrays algorithm

让我们假设我们有一个未排序的整数数组和2个给定的整数L和M.我们的任务是找到具有以下属性的序列a [i] ... a [j]的计数:L< = a [i] + ... + a [j]< = M.

哪种算法最适合解决这个问题?

注意:1< = i< = j< = n且数组的第一个元素是[1],而不是[0]。

2 个答案:

答案 0 :(得分:2)

如果整数都是非负数,则可以使用此算法(伪代码):

countInRange(a, l, m):
    sumL = 0
    count = 0
    idxM = 0
    i = 1
    idxLast = len(a)
    for idxL = 1 to idxLast:
        sumL = sumL + a[idxL]
        while i <= idxLast and sumL >= l:
            if idxM <= idxL:
                idxM = idxL
                sumM = sumL
            while idxM <= idxLast and sumM <= m:
                idxM = idxM + 1
                if idxM > idxLast:
                    break
                sumM = sumM + a[idxM]
            count = count + idxM - idxL
            sumL = sumL - a[i]
            sumM = sumM - a[i]
            i = i + 1
    return count

此算法以 O(n)时间复杂度运行:

总的来说,最里面的循环永远不会超过 n 次。这是因为进入循环时 idxM 的值:

  • 永远不会低于1
  • 永远不会高于 n
  • 始终至少比上次输入循环的时间长一个。

总的来说,中间循环的执行次数也不会超过 n 次,因为它会将 i 增加到 n ,同样显然也是如此对于外循环是真的。

请参阅this implementation in Python on repl.it,它还提供 O(n²)算法,用于检索实际序列本身。请注意,该代码必须适应Python中的零索引数组。

答案 1 :(得分:0)

我想以下算法应该可以胜任。我试图在JS中实现它。它基本上是一个简单的reduce操作,其初始值如{idx:0, len:0, sum:0},并且里面有一个3级嵌套三元组。

出于测试目的,我生成了一个包含1到10之间随机值的30个项目的数组。目前它将结果作为系列,帮助我检查它是否运行良好。然后根据您的要求,系列计数,我们所需要的只是替换最后一个

return r[0].sum < low ? r.slice(1) : r;

对齐
return r[0].sum < low ? r.length-1 : r.length;

function getLimitedSeries(a,low,high){
  var r = a.reduce((p,c,i) => (p[0].sum + c < low ? ( p[0].sum += c,
                                                      p[0].len++
                                                    )
                                                  : p[0].sum + c <= high ? ( p[0].sum += c,
                                                                             p[0].len++,
                                                                             p[0].idx = i-p[0].len+1
                                                                           )
                                                                         : ( p[0].sum >= low && p.push(p[0]),
                                                                             p[0] =  c > high ? {idx:i, len:0, sum:0}
                                                                                              : {idx:i, len:1, sum:c}
                                                                           ),p)
                              , [{idx:0, len:0, sum:0}]);  // initial value of reduce
  return r[0].sum < low ? r.slice(1) : r;
}

var arr = new Array(30).fill().map(e => ~~(Math.random()*10)+1);

console.log(JSON.stringify(arr));
console.log(getLimitedSeries(arr,15,21));