檢測 2 的冪
給定一個整數 x,如何檢測它是不是 2 冪?即是否能夠表示成 2k 的形式,其中 k 是非負整數。
演算法 A
因為 2 的冪不包含 2 以外的素因子,我們有:
- x 必須是正整數。
- 1 = 20 滿足要求。
- 如果 x 是偶數,就一直除以 2,直到 x 變為奇數為止。
- 此時,如果 x = 1,則滿足要求,否則就不滿足要求。
對應的 C 語言程式如下所示:
int isPowerOf2a(long x)
{
if (x <= 0) return 0;
while (x % 2 == 0) x /= 2;
return x == 1;
}
演算法 B
在二進位制計算機上,以上對 2 取模和除以 2 的運算可以使用按位與和向右移位運算代替:
int isPowerOf2b(long x)
{
if (x <= 0) return 0;
while ((x & 1) == 0) x >>= 1;
return x == 1;
}
演算法 A 和演算法 B 的時間複雜度都是 O(log n)。
演算法 C
如果 x = 2k,則它的二進位制表示只含有一個 1,後面跟著 k 個 0。而且 x-1 由 k 個 1 組成。因此,(x & x-1) == 0。如果 x 是正整數,且不是 2 的冪,則 x 的二進位制表示包含不止一個 1。x-1 把 x 從 ???10...0 變為 ???01...1,除了最右邊的 1 變為 0 以外,其餘的 1 不變,所以 (x & x-1) != 0。因此,我們有:
int isPowerOf2c(long x) { return x > 0 && (x & x-1) == 0; }
1 10 11 100 101 110 111 1000 1001 1010 x
0 01 10 011 100 101 110 0111 1000 1001 x-1
0 00 10 000 100 100 110 0000 1000 1000 x & x-1
如果 x 是正整數,則 x & x-1 把 x 的二進位制表示最右端的 1 變為 0。
演算法 D
在二進位制計算機上,如果負數以補碼(即反碼加 1)表示,我們有以下演算法:
int isPowerOf2d(long x) { return x > 0 && (x & -x) == x; }
01 010 011 0100 0101 0110 0111 01000 01001 01010 x
11 110 101 1100 1011 1010 1001 11000 10111 10110 -x
01 010 001 0100 0001 0010 0001 01000 00001 00010 x & -x
如果 x 是正整數,則 x & -x 是 2 的冪,其二進位制表示只包含一個 1,且這個 1 是 x 最右端的 1。也就是說,x & -x 把 x 的二進位制表示中除最右端以外的 1 都變為 0。
演算法 C 和演算法 D 的時間複雜度都是 O(1)。
演算法 A 是通用的,可以用於十進位制計算機。演算法 B、C 和 D 只能用於二進位制計算機。演算法 D 還要求負數以補碼錶示。
測試程式
#include <stdio.h>
#include <time.h>
// 上述 4 個函式放在這裡
void test(char id, int (*isPowerOf2)(long), long max)
{
long z = 0;
clock_t t = clock();
for (long i = 0; i <= max; i++)
if (isPowerOf2(i)) z++;
printf("isPowerOf2%c: %5.1lf seconds, %ld\n",
id, (double)(clock()-t)/CLOCKS_PER_SEC, z);
}
int main(void)
{
long max = 12345678901;
test('a', isPowerOf2a, max);
test('b', isPowerOf2b, max);
test('c', isPowerOf2c, max);
test('d', isPowerOf2d, max);
return 0;
}
編譯和執行
$ clang -O isPowerOf2.c && ./a.out
isPowerOf2a: 49.7 seconds, 34 isPowerOf2b: 41.5 seconds, 34 isPowerOf2c: 29.7 seconds, 34 isPowerOf2d: 32.7 seconds, 34
演算法 C 和演算法 D 的速度差不多,而演算法 A 和演算法 B 也不算太慢。
相關文章
- 2的冪
- DB2 HADR的heartbeat檢測DB2
- leetcode 231 2的冪LeetCode
- 力扣-231. 2 的冪力扣
- WPF 2D 碰撞檢測
- 2.Harris角點檢測
- leetcode231 2的冪(JAVA版)LeetCodeJava
- 人臉檢測的harr檢測函式函式
- 冪的計算
- Pytorch 目標檢測學習 Day 2PyTorch
- 奇異2,3,5次冪構成的恆等式恆等式
- Vitastiq 2可測出身體維生素含量:一支神奇的檢測筆AST
- R2CNN模型——用於文字目標檢測的模型CNN模型
- OPENCV例程2 :CANNY運算元邊緣檢測OpenCV
- HDU 2276 - Kiki & Little Kiki 2 (矩陣快速冪)矩陣
- 檢測-紋理表面凸起、凹痕、劃痕缺陷的檢測
- 快速冪
- OpenCV檢測篇(一)——貓臉檢測OpenCV
- “等一下,我碰!”——常見的2D碰撞檢測
- 文章相似度檢測,相似度檢測工具,原創度檢測工具
- 計算2的N次冪n 可輸入,n為自然數
- 網站漏洞檢測 滲透測試檢測手法網站
- UnityGhost的檢測和回溯Unity
- 影像的邊緣檢測
- 檢測陣列的方法陣列
- Halcon表面缺陷檢測-劃痕檢測
- 微信域名檢測,域名攔截檢測介面
- QQ/微信域名檢測-域名檢測官方介面
- 目標檢測:二維碼檢測方案
- 冪的計算(C#)C#
- mongoDB中的冪等性MongoDB
- 冪等方法的應用
- 冪的一個公式(一)公式
- 冪的一個公式(二)公式
- 【POWER】Oracle的冪運算Oracle
- leedcode-4的冪
- 微信域名檢測線上批次檢測如何實現?——利用域名檢測api介面實現批次檢測工具教程API
- 自媒體文章檢測工具,檢測你的文章,提高你的質量