【发布时间】:2016-10-18 20:43:54
【问题描述】:
假设我们有一个未排序的整数数组和 2 个给定的整数 L 和 M。我们的任务是找到具有以下属性的序列 a[i]...a[j] 的计数:L
哪种算法最适合解决这个问题?
注意:1
【问题讨论】:
-
它看起来像段树的情况。
-
这些整数可以是负数吗?
假设我们有一个未排序的整数数组和 2 个给定的整数 L 和 M。我们的任务是找到具有以下属性的序列 a[i]...a[j] 的计数:L
哪种算法最适合解决这个问题?
注意:1
【问题讨论】:
如果整数都是非负的,你可以使用这个算法(伪代码):
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 中的零索引数组。
【讨论】:
我想下面的算法应该可以完成这项工作。我试图在 JS 中实现它。它基本上是一个单一的 reduce 操作,初始值类似于 {idx:0, len:0, sum:0},内部有一个 3 级嵌套三元组。
出于测试目的,我生成了一个包含 30 个项目的数组,其中随机值介于 1 到 10 之间。目前它以系列形式给出结果,以便您帮助我检查它是否运行良好。然后根据您的要求,系列很重要,我们只需要替换最后一个
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));
【讨论】: