位操作算法解析:获取相邻数值的二进制挑战
问题描述
给定一个正整数,找出与该数具有相同数量1的二进制表示的下一个最大数和下一个最小数。这个问题考察了我们对二进制位操作的理解和运用能力。
约束条件
- 输出必须为正整数
- 输入可能无效,需要进行验证
- 假设内存足够存放处理结果
测试用例
- 无效输入测试:
- None -> 抛出异常
- 0 -> 抛出异常
- 负数 -> 抛出异常
- 常规测试:
- 输入:0000 0000 1101 0111
- 下一个最大数:0000 0000 1101 1011
- 下一个最小数:0000 0000 1100 1111
算法原理
获取下一个最大数
-
寻找关键位:找到最右边的非拖尾0位(即该0位右边至少有一个1)
- 从右向左扫描,统计连续的0的数量
- 接着统计连续的1的数量
- 关键位的位置 = 连续0的数量 + 连续1的数量
-
设置关键位:将关键位设置为1
-
清理右侧位:将关键位右侧的所有位清零
-
重新设置1位:在最低位开始,设置(连续1的数量-1)个1
获取下一个最小数
-
寻找关键位:找到最右边的非拖尾1位(即该1位右边至少有一个0)
- 从右向左扫描,统计连续的1的数量
- 接着统计连续的0的数量
- 关键位的位置 = 连续1的数量 + 连续0的数量
-
清除关键位:将关键位设置为0
-
清理右侧位:将关键位右侧的所有位清零
-
重新设置1位:在最低位开始,设置(连续1的数量+1)个1
复杂度分析
- 时间复杂度:O(b),其中b是数字的二进制位数
- 空间复杂度:O(b),其中b是数字的二进制位数
代码实现
class Bits(object):
def get_next_largest(self, num):
if num is None:
raise TypeError('num cannot be None')
if num <= 0:
raise ValueError('num cannot be 0 or negative')
num_ones = 0
num_zeroes = 0
num_copy = num
# 寻找最右边的非拖尾0位
# 统计右边的连续0数量
while num_copy != 0 and num_copy & 1 == 0:
num_zeroes += 1
num_copy >>= 1
# 统计右边的连续1数量
while num_copy != 0 and num_copy & 1 == 1:
num_ones += 1
num_copy >>= 1
# 确定关键位位置并设置该位
index = num_zeroes + num_ones
num |= 1 << index
# 清除关键位右侧的所有位
num &= ~((1 << index) - 1)
# 从最低位开始设置1
num |= ((1 << num_ones - 1) - 1)
return num
def get_next_smallest(self, num):
if num is None:
raise TypeError('num cannot be None')
if num <= 0:
raise ValueError('num cannot be 0 or negative')
num_ones = 0
num_zeroes = 0
num_copy = num
# 寻找最右边的非拖尾1位
# 统计右边的连续1数量
while num_copy != 0 and num_copy & 1 == 1:
num_ones += 1
num_copy >>= 1
# 统计右边的连续0数量
while num_copy != 0 and num_copy & 1 == 0:
num_zeroes += 1
num_copy >>= 1
# 确定关键位位置并清除该位
index = num_zeroes + num_ones
num &= ~(1 << index)
# 清除关键位右侧的所有位
num &= ~((1 << index) - 1)
# 从最低位开始设置1
num |= (1 << num_ones + 1) - 1
return num
单元测试
import unittest
class TestBits(unittest.TestCase):
def test_get_next_largest(self):
bits = Bits()
self.assertRaises(Exception, bits.get_next_largest, None)
self.assertRaises(Exception, bits.get_next_largest, 0)
self.assertRaises(Exception, bits.get_next_largest, -1)
num = int('011010111', base=2)
expected = int('011011011', base=2)
self.assertEqual(bits.get_next_largest(num), expected)
print('Success: test_get_next_largest')
def test_get_next_smallest(self):
bits = Bits()
self.assertRaises(Exception, bits.get_next_smallest, None)
self.assertRaises(Exception, bits.get_next_smallest, 0)
self.assertRaises(Exception, bits.get_next_smallest, -1)
num = int('011010111', base=2)
expected = int('011001111', base=2)
self.assertEqual(bits.get_next_smallest(num), expected)
print('Success: test_get_next_smallest')
def main():
test = TestBits()
test.test_get_next_largest()
test.test_get_next_smallest()
if __name__ == '__main__':
main()
实际应用
这种位操作技巧在实际开发中有多种应用场景:
- 内存管理:在需要分配特定大小的内存块时,快速找到最合适的块大小
- 哈希算法:优化哈希表的桶大小选择
- 图形处理:处理像素数据时快速调整位模式
- 压缩算法:在位级压缩数据时寻找最优表示
理解这些位操作技巧不仅能帮助我们解决特定问题,还能提升我们对计算机底层数据表示和处理的理解。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考