General method to fit a number into a sequence
一般问题如下。给定正整数0 < s_1 < s_2 < s_3 < ...和正整数n的递增序列,是否存在一种有效的算法来找到(唯一)索引k,使得s_k <= n < s_(k+1)?
使用一个很好的解决方案解决此问题的具体示例是找到二进制扩展的最大非零数字,即先取s_i = 2^(i-1),然后取k = log_2(n)。
一个稍微困难的例子是在阶乘展开中找到最大的非零数字,即取s_i = i!。
我想到的这个问题的示例如下:
s_i = i三角数= 1 + 2 + ... + i = i(i+1)/2
我想要一个很好的解决方案,这意味着比以下更好的东西
1 2 3 4 5
| for(int i=1; ; ++i) {
if (triangle[i] > n)
break;
}
return i; |
注意:由于序列是无限的,因此不能在此处使用二进制搜索。当然,显然存在k <= n的约束,但这通常是一个可怕的局限。例如,如果s_i = i!,则在n=20上使用二进制搜索需要在答案为k=3时计算20!,因此不必在4!之外进行计算。
- 您可以改用二进制搜索,通常速度更快
-
@Nico不,你不能。序列是无限的。
-
哦,对不起,没注意到:)
-
而且,这听起来并不像"您实际面对的实际问题"
一种通用方法:尝试求解方程式n = s(x)和集合k = floor(x)。
对于s_i=2^(i-1),您将得到x=log2(n)+1。对于s_i=i*(i+1)/2,您将得到x=(sqrt(1+8n)-1)/2。
如果该方程在解析上无法求解,请尝试近似(例如牛顿法),或简单地对序列使用二元搜索。
- 一旦不能在无限序列上使用二进制搜索
-
@PengOne:某种二进制搜索。您可以从索引1开始,跳入系数2。然后在有界线段上应用标准二进制搜索。这将限制您的步数与log(n)成比例,其中n是您要查找的数字。
-
通过2因子跳跃的想法有些武断。尝试使用序列s_i = i!。通常,这假设序列在最坏的情况下呈指数增长,这是一个糟糕的假设。
-
感谢您解决三角数问题,但这仍然引出一般情况下该怎么做的问题。
-
@PengOne:不,这里没有假设,并且绑定的O(log n)仍然成立。要按顺序越过值n,您需要进行log2 n步,然后剩下最多包含2n个项目的候选范围。现在,您可以在此范围上应用标准二进制搜索,该搜索也需要花费O(log(n))。
-
如果序列的增长快于或慢于指数增长,那么"跳2"不是一个好方法。
-
@PengOne:为什么不呢?请记住,跳跃在索引上。
-
让我们继续聊天中的讨论。
-
@PengOne:对于比指数慢的增长,跳2是一个很好的策略(可能是最优的)。对于阶乘,它也是完全可以接受的,具有对数线性O(i.Lg(i))行为。对于超指数增长,真正的挑战可能是数字的存储/表示,而不是有效的搜索。