leetcode 342
题目
Given an integer (signed 32 bits), write a function to check whether it is a power of 4.
Example:
Given num = 16, return true. Given num = 5, return false.
Follow up: Could you solve it without loops/recursion?
Credits:
Special thanks to @yukuairoy for adding this problem and creating all test cases.
Subscribe to see which companies asked this question
大意就是如何判断一个数字是不是4的k次幂。进阶版本是如何使用非循环的方法来实现。
本文只介绍如何使用非循环的方式来实现。废话不多说,上代码。
实现
//leetcode 342
bool isPowerOfFour(int num) {
if(num <= 0)return false;
bitset<32> bits(num);
//判断是否为2的幂
if(bits.count() != 1){return false;}
else{
//判断奇数位是否是1
bits = num&0x55555555;
return bits.count() == 1;
}
}
思路
首先小于等于0的数肯定不是4的幂,进行排除。
一个基本思路是首先判断这个数是不是2的幂,然后查看二进制下1的后面是否有偶数个0。
判断是否为2的幂的方法很简单,即查看二进制的数字是否存在且只存在1个1
eg:0000 0010
判断1后面是否存在偶数个0的方法为:num&0x55555555,即判断只有1个1,且其落在奇数位。
eg:0000 0010&0101 0101 = 0000 0000 ,0001 0000&0101 0101 = 0001 0000
拓展
bitset.count()的时间复杂度是什么呢?它会不会直接是一个循环的调用,导致我们写的这份代码只是一个想象中非常美好,却只是一坨X呢?
查看了一下OSX中的STL实现。
<bitset>
template <size_t _Size>
inline _LIBCPP_INLINE_VISIBILITY
size_t
bitset<_Size>::count() const _NOEXCEPT
{
return static_cast<size_t>(_VSTD::count(base::__make_iter(0), base::__make_iter(_Size), true));
}
<algorithm>
template <class _InputIterator, class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
typename iterator_traits<_InputIterator>::difference_type
count(_InputIterator __first, _InputIterator __last, const _Tp& __value_)
{
typename iterator_traits<_InputIterator>::difference_type __r(0);
for (; __first != __last; ++__first)
if (*__first == __value_)
++__r;
return __r;
}
可以看到,这里实现的方式其实是按照会循环执行32次。但是我们只是关注了代码,并未考虑编译器的优化和硬件指令集。
https://www.quora.com/What-is-complexity-of-the-count-function-in-C++-std-bitset,这篇参考文章中说部分硬件会使用精心设计的硬件结构来进行实现count。
例如x86的部分CPU设计了指令popcnt来使用。
http://stackoverflow.com/questions/34407437/what-is-the-efficient-way-to-count-set-bits-at-a-position-or-lower,介绍了不同的有效率的count实现方法。