我有一个数字(在10中),表示为一个最多10 ^ 6位的字符串。我想检查这个数字是否是2的幂。我能想到的一件事是对指数进行二分搜索并使用FFT和快速求幂算法,但编码时间长且复杂。设n表示输入的长度(即输入中的小数位数)。作为n?
的函数,解决这个问题的最有效算法是什么答案 0 :(得分:3)
对于任何给定大小的十进制数,有两个或三个2的幂,并且很容易猜出它们是什么,因为十进制数的大小是其基数10对数的良好近似值,并且您可以通过乘以适当的常数(log 2 10)来计算基数2的对数。因此二元搜索效率低下且不必要。
一旦你有一个试验指数,它将是三百万的量级,你可以使用平方取幂算法和大约22个bugnum十进制乘法。 (最多21次加倍,但这些相对容易。)
根据您执行此检查的频率,您可能希望投资快速bignum代码。但如果不经常,简单的乘法应该没问题。
如果你不希望这些数字是2的幂,你可以先做一个快速计算mod 10 9 ,看看最后9位是否匹配。这将消除所有随机数的百分比。或者,对于更快但稍弱的滤波器,使用64位算术检查最后20位数可以被2 20 整除,而不是10。
答案 1 :(得分:1)
这是一个简单的概率解决方案。
说出您的号码为 // setup an abstract state for the tabs directive
.state('tab', {
url: '/tab',
abstract: true,
templateUrl: 'templates/tabs.html',
})
// Each tab has its own nav history stack:
.state('tab.trips', {
url: '/trips',
views: {
'tab-trips': {
templateUrl: 'templates/trips.html',
controller: 'TripsCtrl',
}
}
})
.state('tab.trip-detail', {
url: '/trips/:tripId',
views: {
'tab-trips': {
templateUrl: 'templates/trip-detail.html',
controller: 'DestinationCtrl',
}
}
})
,我们希望找到n
:k
。显然,n = 2^k
。我们可以估算k = log2(n) = log10(n) * log2(10)
并找出log10(n) ~ len(n)
但有一个小错误(例如,k' = len(n) * log2(10)
,我没有检查,但这应该足够了)。在任何可以想到的解决方案中你可能都需要这个部分,在其他答案中也提到过。
现在让我们检查某些已知|k - k'| <= 5
的{{1}}。从2到n = 2^k
选择一个随机素数k
。如果余数不相等,则P
绝对不匹配。但如果他们是平等的呢?我声称误报率受k^2
的限制。
为什么会这样?因为k
然后2 log(k)/k
除n = 2^k (mod P)
。数字D的长度大约为P
(因为D = n-2^k
和k
由于第一部分而具有相似的大小),因此不能超过n
个不同的素数除数。大约2^k
素数小于k
,因此您随机选择k^2 / log(k^2)
的素数除数的概率小于k^2
。
在实践中,素数高达10 ^ 9(甚至高达D
)就足够了,但你必须做更深入的分析来证明概率。
这个解决方案根本不需要任何长算术,所有计算都可以用64位整数进行。
P.S。为了从1到T选择随机素数,您可以使用以下逻辑:从1到T选择一个随机数并将其递增1直到它为素数。在这种情况下,素数的分布不均匀,前者的分析并不完全正确,但它也可以适应这种随机性。
答案 2 :(得分:0)
我不确定它是否易于应用,但我会按以下方式进行:
1)以二进制显示数字。现在,如果数字是2的幂,它看起来像:
1000000....
只有一个1
,其余为0
。检查这个号码很容易。现在的问题是如何存储号码。例如,它可能有前导零,这将加强对1:
...000010000....
如果只有少量前导零,只需从左到右搜索。如果零的数量未知,我们将不得不......
2)二元搜索1:
2a)在中间切开。2b)如果两者或两者都不为0(希望你能在合理的时间内检查数字是否为零),则停止并返回false。 (假=不是2的力量)
否则继续使用非零部分。
如果非零部分= 1则停止并返回true。
估计:如果数字是n位(十进制),则其2 ^ n位数为二进制。
二进制搜索需要O(log t)
,并且由于t = 2 ^ n,log t = n。因此算法应该采用O(n)
。
假设:
1)您可以访问该号码的二进制视图。
2)您可以在合理的时间内将数字与零进行比较。