简介
题目链接 LeetCode 326. Power of Three
本题的标签是Math
,有多种数学的实现方法,一起看看吧。
注意:文章中一切注解皆为Python代码
理解题目
题目非常简单,判断一个数是不是3的幂。
题目剖析+思考过程
最简单的方法,暴力求解,让n
一直除以3,直到得到小于3的数为止。还有什么数学解法呢?显然用log
也可以。那么我们先给出这两种解法,然后再看看其他新奇的解法。
代码实现(附注释)
解法一:暴力求解
太直白,就不解释了
class Solution:
def isPowerOfThree(self, n: int) -> bool:
while n >= 3 and n % 3 == 0:
n //= 3
return n == 1
解法二:暴力求解的优化
一点点优化,对于比较大的数更好用;一直在增大k
(这里k=3^i,i > 0
),直到不能被整除,再慢慢变回3。
class Solution:
def isPowerOfThree(self, n: int) -> bool:
k = 3
while n >= 3:
if n % k == 0:
n //= k
k *= 3
elif k > 3: k //= 3
else: return False
return n == 1
解法三:数学解法(移项log
)
如果3^k == n
,那么k == log(n) / log(3)
,只要k
是整数就说明n
是3的幂
class Solution:
def isPowerOfThree(self, n: int) -> bool:
if n <= 0: return False
k = log(n, 3)
return abs(k - round(k)) < 1e-10
解法四:位运算
我们都知道,在二进制中,2的幂的表示方式都是10…0(1后面接k个0),例如:
2^0 = 1 = int('1', 2)
2^1 = 2 = int('10', 2)
2^2 = 4 = int('100', 2)
但你可能没有去想过,这样的形式对三进制也是成立的,比如:
3^0 = 1 = int('1', 3)
3^1 = 3 = int('10', 3)
3^2 = 9 = int('100', 3)
因此,我们只需要找出n
的三进制表达式,并且判断它是否符合1后面接k个0这种模式(pattern)就可以了。
class Solution:
def isPowerOfThree(self, n: int) -> bool:
ans = []
while n > 0:
ans.append(n % 3)
n //= 3
return ans and ans[-1] == 1 and sum(ans[:-1]) == 0
这种方法时间复杂度和暴力解法没什么区别,上述代码甚至还要更慢一些,但是思想是非常独特的,这里就提一下。
解法五:质数的数学性质
这个方法就更另类了,我们一直都在想让n
整除3取判断到底是不是3的幂,有没有想过有些数整除n
也可以判断它是3的幂?
首先我们要知道,对于3^k
这样一个数,它的因数全都是3的幂(1除外),因此我们只需要找到一个数3^k
,并确保它大于n
,在判断n
是不是3^k
的因数就好。
为了找到足够大的3的幂,我们可以用int(log(2**31-1, 3))
,代码如下
class Solution:
def isPowerOfThree(self, n: int) -> bool:
return n > 0 and 3**int(log(2**31-1, 3)) % n == 0
这种解法和解法三的数学移向也没什么太大区别,但是利用底数为质数的最大幂数来求解的思想很新颖。
解题后的思考
小小的一题,有这么多种有趣的解法,每个解法各有特色,灵活运用数学才可以创造出更多有趣的解法。