让我们假设我们有一个未排序的整数数组和2个给定的整数L和M.我们的任务是找到具有以下属性的序列a [i] ... a [j]的计数:L< = a [i] + ... + a [j]< = M.
哪种算法最适合解决这个问题?
注意:1< = i< = j< = n且数组的第一个元素是[1],而不是[0]。
答案 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 的值:
总的来说,中间循环的执行次数也不会超过 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));