将循环的线性时间转换为 log(n) 时间函数?
Turning a linear time for loop into a log(n) time function?
在一次采访中,我被要求描述一个函数,该函数可以 return 一个随机数给定一个对象 {names:weights}
作为输入。我将被允许使用一个库来生成 [0,1]
之间的数字,但没有别的。我回答说任务需要分解成:
确保权重是累积的 [0.25, 0.5, 0.25]
-> [0.25, 0.75, 1]
,另存为 c_arr
在 [0,1]
之间生成一个随机数,另存为 val
,然后通过 for 循环遍历我的 c_arr
。如果 val
是 > c_arr
中的 ith
元素,则继续,否则 return 与 ith
元素关联的名称。
我的面试官指出这是可以接受的,但是,问我是否可以使用大 O 表示法阐明其性能。我在这里不是很了解,但回答说应该是线性时间。他回答说这是真的;但是,伪函数可以改进到 log(n)
时间。
据我所知,log(n)
时间意味着不会遍历 [0,1,2,3,4,5,6,7,8...x]
范围内的每个整数,而是遍历 [1,2,4,8,...X]
之类的东西。我不确定这是否经过验证。但即使是这样,我也不确定如何改进伪代码功能,使其不需要以线性方式遍历 c_arr
中的每个元素。
有人可以解释一下吗?
https://softwareengineering.stackexchange.com/questions/150616/get-weighted-random-item/288599
窃取奥里奥尼皇帝的答案[我不相信]:
现在进入有趣的部分。这种方法的效率如何?什么是最有效的解决方案?我的一段代码需要 O(n) 内存和 O(n) 时间的 运行。我不认为它可以用少于 O(n) space 来完成,但时间复杂度可以低得多,实际上是 O(log n)。诀窍是使用二进制搜索而不是常规的 for 循环。
double r = Random.Next() * totalSum;
int lowGuess = 0;
int highGuess = fruit.Count - 1;
while (highGuess >= lowGuess)
{
int guess = (lowGuess + highGuess) / 2;
if ( csum[guess] < r)
lowGuess = guess + 1;
else if ( csum[guess] - weight[guess] > r)
highGuess = guess - 1;
else
return fruit[guess];
}
还有一个关于更新权重的故事。在最坏的情况下,更新一个元素的权重会导致更新所有元素的累积和,从而将更新复杂度增加到 O(n)。这也可以使用二叉索引树减少到 O(log n)。
在一次采访中,我被要求描述一个函数,该函数可以 return 一个随机数给定一个对象 {names:weights}
作为输入。我将被允许使用一个库来生成 [0,1]
之间的数字,但没有别的。我回答说任务需要分解成:
确保权重是累积的
[0.25, 0.5, 0.25]
->[0.25, 0.75, 1]
,另存为c_arr
在
[0,1]
之间生成一个随机数,另存为val
,然后通过 for 循环遍历我的c_arr
。如果val
是 >c_arr
中的ith
元素,则继续,否则 return 与ith
元素关联的名称。
我的面试官指出这是可以接受的,但是,问我是否可以使用大 O 表示法阐明其性能。我在这里不是很了解,但回答说应该是线性时间。他回答说这是真的;但是,伪函数可以改进到 log(n)
时间。
据我所知,log(n)
时间意味着不会遍历 [0,1,2,3,4,5,6,7,8...x]
范围内的每个整数,而是遍历 [1,2,4,8,...X]
之类的东西。我不确定这是否经过验证。但即使是这样,我也不确定如何改进伪代码功能,使其不需要以线性方式遍历 c_arr
中的每个元素。
有人可以解释一下吗?
https://softwareengineering.stackexchange.com/questions/150616/get-weighted-random-item/288599
窃取奥里奥尼皇帝的答案[我不相信]:
现在进入有趣的部分。这种方法的效率如何?什么是最有效的解决方案?我的一段代码需要 O(n) 内存和 O(n) 时间的 运行。我不认为它可以用少于 O(n) space 来完成,但时间复杂度可以低得多,实际上是 O(log n)。诀窍是使用二进制搜索而不是常规的 for 循环。
double r = Random.Next() * totalSum;
int lowGuess = 0;
int highGuess = fruit.Count - 1;
while (highGuess >= lowGuess)
{
int guess = (lowGuess + highGuess) / 2;
if ( csum[guess] < r)
lowGuess = guess + 1;
else if ( csum[guess] - weight[guess] > r)
highGuess = guess - 1;
else
return fruit[guess];
}
还有一个关于更新权重的故事。在最坏的情况下,更新一个元素的权重会导致更新所有元素的累积和,从而将更新复杂度增加到 O(n)。这也可以使用二叉索引树减少到 O(log n)。