给定一个二进制字符串或二进制数字(一个可以任意方式使用它),我需要找出下一个较小的二进制数,但保留原始二进制字符串或数字中的0和1的数量。 / p>
例如
如果给定的二进制数或字符串为11100000,则所需的输出为11010000。
如果给定的二进制数或字符串为11010000,则所需的输出为11001000。
当然,我可以用Brute Force方法做到这一点。但我需要一个更好的解决方案。什么是最佳的做法?我想知道是否有人可以帮助我在O(1)中使用逐位操作来解决这个问题。
答案 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位)。