二进制数具有相同数量的0和1

时间:2014-08-29 17:41:51

标签: algorithm data-structures bit-manipulation

给定一个二进制字符串或二进制数字(一个可以任意方式使用它),我需要找出下一个较小的二进制数,但保留原始二进制字符串或数字中的0和1的数量。 / p>

例如

  

如果给定的二进制数或字符串为11100000,则所需的输出为11010000。

     

如果给定的二进制数或字符串为11010000,则所需的输出为11001000。

当然,我可以用Brute Force方法做到这一点。但我需要一个更好的解决方案。什么是最佳的做法?我想知道是否有人可以帮助我在O(1)中使用逐位操作来解决这个问题。

2 个答案:

答案 0 :(得分:2)

这是对Setzer22答案的详细说明,该答案很接近但缺少一个重要部分。

FindNextSmallestWithSameNumberOfBits(string[1...n])
1. for i = n - 1  to 1 do
2.     if string[i+1] = 0 and string[i] = 1 then
3.         string[i] := 0
4.         string[i+1] := 1
5.         sort(string[i+2...n], descending)
6.         return string[1...n]
7. return "no solution"

这是一个O(n)算法,当输入大小不受限制时,这是一个可证明最优的渐近界限;虽然这在位操作的意义上是“按位”的,但它显然不会使用人们通常认为的“按位操作”。幸运的是,对于可以具有任意长度的输入,在该方法上使用传统的“按位运算”不会有渐近的优势。对于固定长度的输入,渐近分析并不容易应用,在这个问题的另一个答案中,使用诸如Asuka链接的技术可能会做得更好。

请注意,根据注释,第5行的排序可以通过简单地反转字符串来替换。这样做的原因是该子字符串保证为0...01...1形式(即任何0 s左侧的任何1),因为如果不是,我们已经找到了字符串10的出现并且满足了第2行的条件。

Setzer22的答案中缺少的关键是,一旦你向右移动最右边的1并向右移动0,你就需要左移所有{ {1}}它们离他们将要走得更远。这样做的原因是向右移位的1位比它右边的位更重要,因此左移任何不太重要的1将给出更大的数字,但不足以消除减少更重要位的影响。

基于注释的澄清:请注意,在上面提到的伪代码的第7行中,算法可能不会返回有效的字符串。这样做的原因是,有时候,没有字符串具有相同数量的1 s代表较小的数字。当且仅当字符串1未在输入字符串中显示为子字符串时才会出现这种情况(在这种情况下,第2行的条件永远不会得到满足)。

这不是有史以来最明确的解释,所以如果需要更多工作,请告诉我。这是一个例子:

01

澄清刚刚发生的一种方法:右移10011 // input 01011 // right-shift the right-most 1 bit with a 0 to the right of it 01110 // left-shift all 1 bits to the right of the right-shifted as far as possible 1010100011 // input 1010010011 // right-shift the right-most 1 bit with a 0 to the right of it 1010011100 // left-shift all 1 bits to the right of the right-shifted bit as far as possible 位保证结果小于原始数字;向右移动1 s保证结果不会小于必要的结果。

答案 1 :(得分:0)

可能这就是你所发现的:

http://www.hackersdelight.org/hdcodetxt/snoob.c.txt

函数snoob()snoob1()snoob2()snoob3()snoob4()next_set_of_n_elements()是各种实现。

这些函数是辅助函数,由上述函数调用:

  • ntz()代表"尾随零的数量"
  • nlz()代表"前导零的数量"
  • pop()代表"人口数" (字符串集的数量(" 1" s的数量))

这非常有效,但仅适用于修复大小整数(例如32位,64位)。