关于算法:将数字拟合到序列中的一般方法

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!之外进行计算。


一种通用方法:尝试求解方程式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

如果该方程在解析上无法求解,请尝试近似(例如牛顿法),或简单地对序列使用二元搜索。