这是interview question:“给定2个整数x和y,检查x是否为y的整数幂”(例如,对于x = 8且y = 2,答案为“true”,对于x = 10且y = 2“假”)。
显而易见的解决方案是:
int n = y; while(n < x) n *= y; return n == x
现在我正在考虑如何改进它。
当然,我可以检查一些特殊情况:例如x
和y
都应为奇数或偶数,即我们可以检查x
和y
的最低有效位。但是我想知道我是否可以改进核心算法本身。
答案 0 :(得分:26)
你最好重复将y分成x。第一次得到非零余数时,你知道x不是y的整数幂。
while (x%y == 0) x = x / y
return x == 1
这将处理第一次迭代时的奇数/偶数点。
答案 1 :(得分:21)
表示 log y (x)应为整数。不需要任何循环。在 O(1)时间
public class PowerTest {
public static boolean isPower(int x, int y) {
double d = Math.log(Math.abs(x)) / Math.log(Math.abs(y));
if ((x > 0 && y > 0) || (x < 0 && y < 0)) {
if (d == (int) d) {
return true;
} else {
return false;
}
} else if (x > 0 && y < 0) {
if ((int) d % 2 == 0) {
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* @param args
*/
public static void main(String[] args) {
System.out.println(isPower(-32, -2));
System.out.println(isPower(2, 8));
System.out.println(isPower(8, 12));
System.out.println(isPower(9, 9));
System.out.println(isPower(-16, 2));
System.out.println(isPower(-8, -2));
System.out.println(isPower(16, -2));
System.out.println(isPower(8, -2));
}
}
答案 2 :(得分:7)
这将以O(log N)步骤查找指数:
#define MAX_POWERS 100
int is_power(unsigned long x, unsigned long y) {
int i;
unsigned long powers[MAX_POWERS];
unsigned long last;
last = powers[0] = y;
for (i = 1; last < x; i++) {
last *= last; // note that last * last can overflow here!
powers[i] = last;
}
while (x >= y) {
unsigned long top = powers[--i];
if (x >= top) {
unsigned long x1 = x / top;
if (x1 * top != x) return 0;
x = x1;
}
}
return (x == 1);
}
此代码不处理负数,但在i = 1
答案 3 :(得分:4)
double a=8;
double b=64;
double n = Math.log(b)/Math.log(a);
double e = Math.ceil(n);
if((n/e) == 1){
System.out.println("true");
} else{
System.out.println("false");
}
答案 4 :(得分:3)
对于正数,这看起来非常快,因为它找到所需功率的下限和上限,然后应用二进制搜索。
#include <iostream>
#include <cmath>
using namespace std;
//x is the dividend, y the divisor.
bool isIntegerPower(int x, int y)
{
int low = 0, high;
int exp = 1;
int val = y;
//Loop by changing exponent in the powers of 2 and
//Find out low and high exponents between which the required exponent lies.
while(1)
{
val = pow((double)y, exp);
if(val == x)
return true;
else if(val > x)
break;
low = exp;
exp = exp * 2;
high = exp;
}
//Use binary search to find out the actual integer exponent if exists
//Otherwise, return false as no integer power.
int mid = (low + high)/2;
while(low < high)
{
val = pow((double)y, mid);
if(val > x)
{
high = mid-1;
}
else if(val == x)
{
return true;
}
else if(val < x)
{
low = mid+1;
}
mid = (low + high)/2;
}
return false;
}
int main()
{
cout<<isIntegerPower(1024,2);
}
答案 5 :(得分:2)
我会像这样实现这个功能:
bool IsWholeNumberPower(int x, int y)
{
double power = log(x)/log(y);
return floor(power) == power;
}
这不应该像在浮点比较中那样在delta中检查,因为我们正在检查整数。
答案 6 :(得分:2)
再想一想,不要这样做。它不适用于否定x
和/或y
。 请注意,现在提供的所有其他基于log
的答案也会以完全相同的方式中断。
以下是快速通用解决方案(使用Java):
static boolean isPow(int x, int y) {
int logyx = (int)(Math.log(x) / Math.log(y));
return pow(y, logyx) == x || pow(y, logyx + 1) == x;
}
其中pow()
是整数取幂函数,如Java中的以下内容:
static int pow(int a, int b) {
return (int)Math.pow(a, b);
}
(这是由于Math.pow
提供的以下保证:“如果两个参数都是整数,那么结果完全等于将第一个参数提升到第二个参数的幂的数学结果。 。“)
使用对数而不是重复除法的原因是性能:log is slower than division时,它会慢一个小的固定倍数。同时它确实消除了对循环的需要,因此为您提供了一个恒定时间算法。
击>
答案 7 :(得分:2)
在y
为2的情况下,有一种快速方法可以避免需要循环。这种方法可以扩展到y
具有2的更大幂的情况。
如果x
是2的幂,则x
的二进制表示只有一个设置位。有一个相当简单的bit-fiddling算法,用于在O(log n)时间内对整数中的位进行计数,其中n是整数的位宽。许多处理器也有专门的指令,可以将其作为单个操作处理,大约与(例如)整数否定一样快。
然而,为了扩展该方法,首先采用略微不同的方法来检查单个位。首先确定最低有效位的位置。同样,有一个简单的比特摆弄算法,许多处理器都有快速的专用指令。
如果该位是唯一位,则为(1 << pos) == x
。这里的优点是,如果你测试的是4的幂,你可以测试pos % 2 == 0
(单个位在偶数位置)。测试任何2的幂,你可以测试pos % (y >> 1) == 0
。
原则上,你可以做类似的事情来测试3的幂和3的幂。问题是你需要一个在3号基础上工作的机器,这有点不太可能。您当然可以测试任何值x
,看看它在基础y
中的表示是否只有一个非零数字,但您要做的工作更多,而您已经在做了。以上内容利用了计算机以二进制方式工作的事实。
可能不值得在现实世界中做。
答案 8 :(得分:2)
这是一个Python版本,汇集了@salva和@Axn的想法,并被修改为不生成任何大于给定数字的数字,并且仅使用简单存储(读取,&#34;无列表&#34;)反复削减兴趣的数量:
def perfect_base(b, n):
"""Returns True if integer n can be expressed as b**e where
n is a positive integer, else False."""
assert b > 1 and n >= b and int(n) == n and int(b) == b
# parity check
if not b % 2:
if n % 2:
return False # b,n is even,odd
if b == 2:
return n & (n - 1) == 0
if not b & (b - 1) and n & (n - 1):
return False # b == 2**m but n != 2**M
elif not n % 2:
return False # b,n is odd,even
while n >= b:
d = b
while d <= n:
n, r = divmod(n, d)
if r:
return False
d *= d
return n == 1
答案 9 :(得分:1)
以前的答案都是正确的,我喜欢Paul的最佳答案。它简单而干净。 以下是他建议的Java实现:
public static boolean isPowerOfaNumber(int baseOrg, int powerOrg) {
double base = baseOrg;
double power = powerOrg;
while (base % power == 0)
base = base / power;
// return true if base is equal 1
return base == 1;
}
答案 10 :(得分:1)
如果数字太大,请使用日志功能以减少时间复杂度:
import math
base = int(input("Enter the base number: "))
for i in range(base,int(input("Enter the end of range: "))+1):
if(math.log(i) / math.log(base) % 1 == 0 ):
print(i)
答案 11 :(得分:0)
如果您可以访问y
的最大功率,可以在所需的数据类型中使用,这是解决此问题的一种非常灵活的方法。
让我们说,y == 3
。因此,我们需要检查x
是否为3的幂。
鉴于我们需要检查整数x
是否为3的幂,让我们从已经掌握的信息开始考虑这个问题。
1162261467是3中最大的幂,可以放入Java int。
1162261467 = 3^19 + 0
给定的x可以表示为[(a power of 3) + (some n)]
。我认为能够证明如果n为0(发生 iff x是3的幂),1162261467 % x = 0
就足够了。
因此,要检查给定的整数x
是否为3的幂,请检查x > 0 && 1162261467 % x == 0
是否。
泛化。要检查给定的整数x
是否是给定整数y
的幂,请检查x > 0 && Y % x == 0
:Y
是否是y
的最大幂整数数据类型。
一般的想法是,如果A
具有Y
的某种能力,则A可以表示为B/Ya
,其中a是某个整数且A < B
。它遵循A > B
完全相同的原则。 A = B
案例是基本的。
答案 12 :(得分:0)
我找到了这个解决方案 //检查如果A可以表示为两个整数的幂
int isPower(int A)
{
int i,a;
double p;
if(A==1)
return 1;
for(int a=1; a<=sqrt(A);++a )
{
p=log(A)/log(a);
if(p-int(p)<0.000000001)
return 1;
}
return 0;
}