Description

Given an integer n, return true if it is a power of two. Otherwise, return false.

An integer n is a power of two, if there exists an integer x such that n == 2x.

Example 1:

  • Input: n = 1
  • Output: true
  • Explanation: 20 = 1

Example 2:

  • Input: n = 16
  • Output: true
  • Explanation: 24 = 16

Example 3:

  • Input: n = 3
  • Output: false

Constraints:

  • -231 <= n <= 231 - 1

Follow up: Could you solve it without loops/recursion?

Submitted Code

class Solution(object):
    def isPowerOfTwo(self, n):
        """
        :type n: int
        :rtype: bool
        """
        if n <= 0:
            return False
        epsilon = 1e-12
        log_val = math.log(n, 2)
        return abs(round(log_val) - log_val) < epsilon

Runtime: 0 ms | Beats 100.00%
Memory: 12.50 MB | Beats 10.39%

처음에는 n = 2x 이기 때문에 이를 x = log2n 으로 변경한 뒤, .is_integer() 함수로 x가 정수인지 확인하는 방법을 사용했다. 하지만 n이 2의 거듭제곱임에도 부동소수점 오차때문에 x가 실수로 계산되는 케이스가 있었다. 이 경우 x를 정수로 반올림한 값과 실제 x값의 차이가 충분히 작다면 오차를 허용하는 방법을 사용할 수 있다. 엡실론 값을 1e-9로 했을 때는 n = 2147483647일 때 실패했고, 1e-12까지 정밀도를 높였을 때 모든 케이스를 통과했다.

Other Solutions

1st

class Solution:
    def isPowerOfTwo(self, n: int) -> bool:
        return n > 0 and (n & (n - 1)) == 0

time complexity: 𝑂(1)
space complexity: 𝑂(1)

class Solution:
    def isPowerOfTwo(self, n: int) -> bool:
        if n <= 0:
            return False
        cnt = bin(n).count('1')
        return cnt == 1

time complexity: 𝑂(𝑘) ← 𝑘(n의 비트 수) = log2𝑛
space complexity: 𝑂(𝑘)

비트 연산 방식이 더 빠르고 오차없이 정확하기 때문에 좋은 것 같다. 활용된 원리는 2의 거듭제곱 수는 이진수에서 딱 하나의 비트만 1이라는 것이다. 첫 번째 코드는 n과 n-1의 AND 연산 결과가 0일 경우 True를 반환하는 것이고, 두 번째 코드는 n을 2진수 문자열로 변환한 뒤 1의 개수가 1일 때만 True를 반환한다.

n = 8 (1000)

n     (8) = 1000 
n - 1 (7) = 0111
----------------
↓
n & (n-1) = 0000

Leave a comment