我们得到一个子程序,它接受两个正的int参数并返回一个int,假设它是
def f(m,n): return (m+n)**2-n**2
。输入值必须是正整数。相对于两个输入,返回的值都在增加:f(m,n)<f(m+1,n)
和f(m,n)<f(m,n+1)
适用于所有m
和所有n
。我们希望以递增的顺序迭代所有可能的m
和n
对,直到它通过测试为止。我们不关心测试:我们知道一对值将通过它,我们想要通过的最小返回值。我们也不知道测试是否会在每个m
和n
的前一百万个值中传递,因此我们不能只构建整个值列表并对其进行排序。我们如何以合理有效的方式以正确的顺序迭代
m,n
?
我把它想象成一个多队列,它不能是正确的名称:它叫什么?
我有一个由nextN[]
编制索引的数组m-1
,为n
存储访问量最大的m
。由nextV[]
索引的另一个数组m-1
存储f(m,nextN[m-1])
的返回值,因此我们不会为任何一对调用f()
多次(这可以作为预先删除优化,但当f
需要很长时间才能运行或有副作用时,这是必要的优化。在每个步骤中,我们采用最小的存储值并对其进行测试,并使用下一个值n
更新两个数组中的元素。
问题是:应该使用哪些数据结构和方法来使这个多队列高效且易于理解?我有快速入侵,但我想要一个更好,更易理解和可维护的解决方案。
我用Python编写,但同样的问题适用于Java,C等。用你喜欢的任何语言给出答案。 (我不会选择以其默默无闻的语言选择的答案,但如果我能理解它并且有帮助,我会给它+1。)
以下是一些示例代码:
from array import array
from math import sqrt
def findSmallestV(f,test):
# initialize with m,n=1,1 filled out
nextN = array('I', [1])
nextV = array('I', [f(1,1)])
while True:
v = min(nextV)
m = nextV.index(v)+1
n = nextN[m-1]
if test(v):
return (m,n,v)
nextN[m-1] += 1
nextV[m-1] = f(m,n+1)
# if we've just operated on the last column, put a value into the next column
if m == len(nextN):
nextN.append(1)
nextV.append(f(m+1,1))
# example value function
def g(m,n): return (m+n)**2-n**2
# example test function
def h(v): return len(str(v))>5 and int(sqrt(v))**2 == v
ans = findSmallestV(g,h)
print("Smallest V: m=%d, n=%d -> %d" % ans)
当min(nextV)
的大小变大时,我觉得这会花费很长时间nextV
。什么是更好的方式?
答案 0 :(得分:1)
您可以做的是将问题分解为两个步骤:
你也可以在第一部分使用二进制搜索技术。
很难知道“通过测试”意味着什么。你知道返回的值是太大还是太小?如果是这样,您可以通过减半或加倍来调整m
和n
,直到找到解决方案。
鉴于您的限制(即您描述的关系),对两个变量的二元搜索不应该太困难。
您可以跟踪优先级队列中的中间传递值。因此,当您找到一个通过时,您可以将其放入队列。这可能是您下一次的起点。您还需要跟踪已找到的最高和最低通过值,以便更轻松地对搜索进行括号。
而且,我想,你会想要保留某种哈希表,这会阻止你多次生成相同的(m,n)
。
如果m
和n
有一定的范围,这会变得更容易。如果它是“所有正整数”,我所描述的技术是可能的,但如果它们被置于括号内则会更容易。
答案 1 :(得分:1)
评论中建议的优先级队列可以提供一个很好的解决方案。
在算法运行期间的任何时候,您都会考虑一些点而不考虑其他点。您将把这个鸿沟的边界上的点放入优先级队列。更具体地说,您维护一个三元组(m,n,v)的优先级队列(可能实现为二进制堆),按v排序,其中(m,n)是此边界上的一个点,v是其值。
在每次迭代中,从队列中提取最低值的点并对其进行测试。如果它通过,那就是答案。如果没有,请将其右侧和上方的点连同它们的值一起放入队列中。
这将按原样运行,但效率低,因为每个点都会被处理多次。为了防止这种情况发生,还要在队列中的每个列中维护最低坐标的可增长数组,并在每行中保留最左边条目的数组。无论何时向队列输入一个点,首先要检查该列中是否已经存在较低点,或者同一行中是否存在更左侧的点。如果是这样,就不要输入它 - 无论如何它会在以后出现。