【问题标题】:quickly calculate a point of intersection over two arithmetic progressions快速计算两个算术级数的交点
【发布时间】:2012-12-25 15:41:50
【问题描述】:

进度 A 遵循以下规则:
每个值都是加在一起的所有奇数值,包括 N sub i 。

N 次 4。 1+3+5+7 = 16

进度 B 遵循此规则。 取平方根乘以 2 加 1 的上限。从天花板尖齿本身中减去 N。继续添加奇数。

N =33.
天花板(√33) =6.
6*2+1=13.
36-33=3.
3+13 =16。

停止,因为 16 在进程 A 和 B 中。是否可以快速执行此操作? IE。最小的 1 步或 2 步解决方案? java 或通用实现会很方便

*问题*

What is the output you desire? Simply abool saying they do meet? Or do you want the indices at which they do meet, i.e.A[4]=16 andB[17]=16? Or do you just want the number at which they meet, i.e.16? And what if they don't meet exactly? Do you want the indices (or number) before, or after, the intersection? Finally, when or how do you decide to halt, if, say, the two sequences will never meet? (I know in this case they do, but I mean in the general case.)

我期望的输出将是值 16 或者它可能是 B 找到该值的索引,因为两者都是等价的,因为索引只是第 i 个术语。如果他们不见面,我意识到这是一个非终止程序。这种情况我不在乎。

【问题讨论】:

  • 你想要的输出是什么?只是一个bool 说他们 见面?或者你想要他们确实相遇的索引,A[4]=16B[17]=16?或者您只是想要他们见面的号码, 16?如果他们不完全见面怎么办?你想要在交叉点之前还是之后的索引(或数字)?最后,如果两个序列永远不会相遇,您何时或如何决定停止? (我知道在这种情况下他们会这样做,但我的意思是在一般情况下。)
  • @acheong87。更新了我的帖子来回复你
  • 您打算概括什么?显然您已经知道解决方案:16。 “Progression B”会在你的下一个项目中发生什么变化吗?
  • “算术级数”是一个具有严格定义含义的数学术语。您在问题中描述的不是算术级数。
  • @acheong87。啊,是的,进展 B 将是改变的部分。随后的进程 A 每次都是相同的,只要它总是从 1 开始。

标签: java performance algorithm math


【解决方案1】:

我将在这里总结我的 cmets,以便新访问者更容易理解。

正如其他人所指出的,序列A只是一个正方形序列;正如 OP 通过他的 cmets 阐明的那样,序列 B 将不断变化。

可能是对 OP 问题的重述

有没有比计算序列的每一项更快的方法来确定递增序列中的第一个方格?

确实有。显而易见的想法是设计一种方法来“跳过”某些项的计算,基于对平方增长率与序列的洞察力。但是很难以编程方式获得关于任意序列的洞察力。

一个更稳健的解决方案可能是将问题重新表述为找到以下的最小零:

B(x) - x^2 = 0

为此,可能存在root-finding algorithms 可能会有所帮助。如果您不需要找到 最小 零,那么更简单:实现任何求根算法,观察算法收敛到零,添加 x^2 以补偿重新公式化,然后你有它。


编辑

(评论框太有限,无法回复你的。)

当我说“二分法”时,我实际上是指“二分搜索”。这需要一个上限,因此并不真正适用于您的问题。

让我提供一个简单的算法作为开始,尽管您可能已经完全想到了这一点。

  1. 计算B(1)。说它是1692(不是正方形)。
  2. 计算B(2)。说它是1707(不是正方形)。
  3. 计算B(2)-B(1),将其称为“delta”,例如 1707-1692,或15。考虑这是对B 增长率的幼稚估计。当然,这几乎肯定是错误的,但我们的目标只是某种跳过术语的方法。这就是稍后要优化的内容。
  4. 下一个大于1707 的平方是多少?公式(floor(sqrt(1707))+1)^2 产生1764
  5. 我们应该跳过多少个词来尝试到达那个正方形?另一个公式(1764-1707)/15 产生3.8,我们可以将其四舍五入为4
  6. 计算B(2+4) = B(6)
    1. 如果小于1764,那么你需要继续。但是在这种情况下,您已经节省了计算 3 个项的时间。你选择如何继续前进,只是另一种选择。您可以计算 B(7) 并转到第 3 步(将 B(7)-B(6) 计算为新的增量)。您可以直接进入第 3 步(将(B(6)-B(2))/4 计算为新的增量)。 (如果不表征B 的可能功能,您将无法真正知道什么是最好的。)
    2. 如果大于1764,那么你需要返回。再次,有很多方法。二分查找实际上是一种简单、合理的方法。计算B(4),因为它直接位于B(2)B(6) 之间。如果小于1764,请尝试B(5)。如果大于1764,请尝试B(3)。如果其中一个不匹配,则从B(7) 开始。使用二分搜索,您最多可以进行log(N) 计算。

所以这听起来很划算,对吧?你要么跳过一些计算,要么最多做log(N)。 (或者,你会找到更好的优化。)但是,显然,它不是那么简单,因为你正在做额外的计算来找到这些增量、投影、二分搜索等。由于正方形增长非常缓慢(只有平方之间有这么多整数),我觉得这样的算法只会在处理大整数或B 的极其复杂的序列时击败“线性搜索”(计算每个术语)(但鉴于B 有总是增加,一个序列到底有多复杂?)关键是找到一个适合所有序列的表征,并通过找到特定的优化来利用那个给它。

我仍然不知道您的应用程序是什么,但此时您不妨尝试一下并在实际数据集上对其进行基准测试(相对于线性搜索)。这将立即告诉您是否有任何实际收益,以及是否应该在优化上投入更多时间。而且它会比尝试做所有的理论数学、表征序列等等更快。

【讨论】:

  • 不确定“单调递增序列”...其实问题中提到的第二个序列(33 -> 16)不是单调的。
  • @ft1 - 哎呀,我不假思索地用了一个花哨的词;谢谢,已编辑。
  • 嗯,我可以在这个上使用二分法还是我误解了这个功能。
  • @Woot4Moo - 总结一下我的编辑,一个简单的算法是(1)项目,(2a)继续或(2b)平分。 (毕竟,我了解到“二等分”实际上可能是一个有效的术语。)
【解决方案2】:

仅供参考,您的第一个序列只是正方形。

应该清楚这两个序列都是单调递增的。因此,您需要做的就是在每个序列中保留一个索引,并重复递增指向较小数字的索引,直到两个索引都指向相同的数字。

请注意,如果序列没有共同的数字,这将永远运行。

【讨论】:

  • 我知道它将永远运行。我的问题更多的是如何确定重叠发生的位置以及如何在不检查每个点的情况下计算该点。
【解决方案3】:

伪代码算法:

int i=1, j=1;
int x=func1(i), y=func2(j);
while x!=y {
  if x<y {i++; x=func1(i)}
  else   {j++; y=func2(j)}
}

假设我们只知道func1func2 是递增函数,则很难进一步优化该算法。

【讨论】:

  • 我认为他知道基本算法,但他正在寻找优化。将问题改写为“有效地找到序列中的第一个完美正方形”,我认为不会失去希望,因为可能会有更好的方法。
  • 线性时间算法有什么低效之处?我看不出如何在没有要比较的值的情况下找到交点。也许这个算法很慢,但如果没有更有效的解决方案,那么这将使其成为最有效的解决方案,对吧?
  • 我并不是说您的解决方案效率低下;我只是说OP正在寻找更快的东西。我不确定是什么让您如此确定没有更有效的解决方案。当您知道问题的某些独特属性时,您通常能够使用该特定知识进行优化,而牺牲一般性。例如,当您知道列表已排序时,突然您可以使用二分法(不确定这是不是正确的术语)来查找列表中是否存在数字,而不进行比较每个值。同样,正方形的属性可能会导致这里发生一些事情。
猜你喜欢
  • 2010-12-23
  • 1970-01-01
  • 2020-02-22
  • 2021-08-23
  • 1970-01-01
  • 2016-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多