给定一个数组 A 和 m 个查询
Posted
技术标签:
【中文标题】给定一个数组 A 和 m 个查询【英文标题】:Given an array A and m queries 【发布时间】:2019-06-06 12:09:32 【问题描述】:每个查询都是整数T
为每个查询找到索引 i 和 j 使得
| (|sum of elements from i to j| - T) |
最小
哪里 |x|是 abs(x) 并且数组也可以有负数
我在直接面试中被问到这个问题。 我有找到所有可能的总和并存储它们的索引和排序的解决方案。
所以可能有 n*n 个总和。
这需要 O(n* n* log(n*n))
现在对于每个查询二进制搜索 T 。那将是 O(m* log(n*n))
但他要求优化它。我没有清除回合。
谁能给出提示?
【问题讨论】:
不能为负数吗? 数组的大小可以有多大?也许你可以增加平均。通过将总和存储在地图中以避免重复来提高案例性能。这减少了没有。总和一点。将每个总和转换为正数,因为无论如何我们都要取绝对值。我想到了分段树,但除非我们找到分解 T 的方法,否则这无济于事。 我要求约束,但面试官要求先告诉方法。他说要减少到n*n以下 因为我没有走得更远,所以我没想过要问 T 的范围。你现在能假设它是积极的吗?抱歉 @JimMischel 对于负 T,我们的任务是最小化子数组和的绝对值,它有一个 O(n log n) 解。 【参考方案1】:如果我们sort the partial sums,例如,
A = [2, -4, 6, -3, 9]
ps = [2, -2, 4, 1, 10]
sorted = [-2, 1, 2, 4, 10]
和的最小绝对值表示部分和之间的最小差值;在这种情况下,1 和 2,表示总和:
-4 + 6 - 3 = -1
由于我们希望最小化和的另一个绝对值,因此我们希望找到最接近T
的绝对和差。我无法找到一个参考来找到与小于O(n) time 的常数相差最接近的一对,因此,这种方法似乎并不比 O(n * log n + n * m) 好。也许我们可以首先利用哈希或排序查询,因为在我们的搜索过程中,彼此接近的查询代表近距离,但我不确定如何。
【讨论】:
好的,谢谢。复杂度也将是 O(n * log n + m* log n) ?其中 m 是查询数 在这种情况下如果 T=9 或大于 9 会怎样 @JitendraKumhar 你是对的。对部分和的差异进行排序不是正确的方法,因为它们有 O(n^2) 个。相反,我们需要在这些差异中进行搜索。我会编辑。 我接受这个答案,因为我认为这是可以实现的最好的。而且我认为面试官只是期望这个 @JitendraKumhar 听起来不错。谢谢你让我知道。另外,我想提一下,虽然我一般不喜欢这种解决方案,但在范围足够有限的情况下,我认为我们还可以使用 FFT 更有效地记录所有前缀和可能性,并拥有它们可以通过这种方式订购和搜索。【参考方案2】:编辑:我认为解决所有问题实际上是巨大的浪费工作。只有当 m >> n 时才有意义。否则这是我的解决方案。
想象一下兔子和乌龟之间的比赛。我希望你知道这个故事... 所以野兔“i”让乌龟“j”先走。他知道他跑得更快,而且他可以打个盹。他只担心乌龟不在视线范围内,“T”米远,然后他跑得很快,直到他看到乌龟并再次入睡......等等。
所以初始化
i = 0
j = 0
bestval = inf
index = none
diff = T
主循环
while(true):
if diff < 0:
i++
diff += A[i]
elif j==n:
break
else:
j++
diff += A[j]
# record best distance
if abs(diff) < bestval:
bestval = diff
index = (i, j)
你不能错过最佳的,因为你没有在增加 abs(diff) 的方向上扩展研究。如果你已经有太多了,继续求和是没有意义的......
所以你只用 j 和 i 在 A 上运行两次,每个 T 一次。这应该是 O(mn)。如果 diff = 0,你甚至可以中断循环。
【讨论】:
我不明白我们如何保证在不使用i
撤退的情况下找到最佳差异(使您的想法 O(n^2) 每个查询)。你能解释一下为什么i
在我们迭代j
时只需要增加而不需要减少吗?
如果数组中有负数,这不起作用。
哦,你是对的,我错过了 A 可能是负数。此解决方案无法检测到可以最佳平衡总和的远负数。以上是关于给定一个数组 A 和 m 个查询的主要内容,如果未能解决你的问题,请参考以下文章