Flip Bit to Win:将一个整数中的某一比特位置位,输入该整数的二进制表示中最长的比特位为1
的长度。
可以把int
转换为0
、1
序列长度的表示方式,然后依次尝试将0
序列中最左或者最右的0
置位,并和左右两部分的1
序列合并,最终找出最大值,算法的时间复杂度为O(b)
,空间复杂度也为O(b)
,其中b
表示输入数据以比特位表示的长度,也可以视为O(1)
。
class Solution {
public:
int reverseBits(int num) {
calSeqLength(num);
int ret = 0;
for(size_t i = 0; i < vecSeqLen.size(); i += 2)
{
int left = i >= 1 ? vecSeqLen[i - 1] : 0;
int right = i + 1 < vecSeqLen.size() ? vecSeqLen[i + 1] : 0;
int total;
if(vecSeqLen[i] == 1) total = left + right + 1;
else {
if(left > right) total = left + 1;
else total = right + 1;
}
if(total > ret) ret = total;
}
return ret;
}
private:
vector<int> vecSeqLen;
void calSeqLength(int num)
{
bool bSearch = false;
int cnt = 0;
for(int idx = 0; idx < sizeof(decltype(num)) * 8; idx++)
{
if((num & 0x1) != bSearch){
vecSeqLen.push_back(cnt);
bSearch = !bSearch;
cnt = 0;
}
cnt++;
num >>= 1;
}
vecSeqLen.push_back(cnt);
}
};
可以优化一下,把空间复杂度降低为纯O(1)
的,从右向左扫描每一位,使用curr
记录当前1
序列的长度,prev
记录紧邻当前序列右侧第1
个0
的1
序列长度。curr + 1 + prev
可以表示翻转curr
和prev
之间的0
,但是不存在prev
序列时,curr + 1 + prev
可以表示翻转curr
位置上的0
,因此两种情况的代码是一致的。
class Solution {
public:
int reverseBits(int num) {
if(num == INT_MAX) return sizeof(decltype(num)) * 8;
int curr = 0, prev = 0;
int ret = 0;
while(num != 0){
if((num & 0x1) == 1) curr++;
else{
if(ret < curr + 1 + prev) ret = curr + 1 + prev;
prev = curr;
curr = 0;
}
num >>= 1;
}
if(ret < curr + 1 + prev) ret = curr + 1 + prev;
return ret;
}
};