给定数字x,请在二进制表示形式中查找具有1位相同数字的下一个数字。
例如,考虑x = 12,其二进制表示形式为1100(不包括32位计算机上的前导零)。它包含两个逻辑1位。具有两个逻辑1位的下一个更高的数字是17(10001 2 )。
算法:
当我们观察从0到2 n – 1的二进制序列(n是位数)时,最右边的位(最低有效位)比最左边的位变化快。这个想法是在x中找到最右边的1的字符串,并将模式移到最右端,除了模式中最左边的位。将模式中最左边的位(忽略的位)向x的左部分移动一个位置。一个例子更清楚地说明了这一点,
x = 156
10
x = 10011100
(2)
10011100
00011100 - right most string of 1's in x
00000011 - right shifted pattern except left most bit ------> [A]
00010000 - isolated left most bit of right most 1's pattern
00100000 - shiftleft-ed the isolated bit by one position ------> [B]
10000000 - left part of x, excluding right most 1's pattern ------> [C]
10100000 - add B and C (OR operation) ------> [D]
10100011 - add A and D which is required number 163
(10)
经过少量实例练习后,它很容易理解。使用以下给定的程序生成更多集合。
程序设计:
我们需要注意一些二进制数的事实。表达式x&-x将隔离x中最右边的设置位(确保x将对负数使用2的补码形式)。如果将结果加到x,将重置x中最右边的1的字符串,并将设置此1的模式左边的立即数“ 0”,这是上述说明的[B]部分。例如,如果x = 156,则x&-x将得到00000100,将此结果加到x上将得出10100000(请参阅D部分)。我们留下了1的模式的右移部分(上述说明的A部分)。
有多种方法可以实现A部分。右移本质上是一种除法运算。我们的除数应该是多少?显然,它应该是2的倍数(避免右移0.5个错误),并且应该将最右边的1的模式转移到最右端。表达式(x&-x)将用于除数的目的。在数字X和用于重置最右边的位的表达式之间的EX-OR运算将隔离最右边的1的模式。
校正因子:
注意,我们将最右边的设置位添加到位模式中。加法运算引起位位置的偏移。二进制系统的权重为2,一移位会导致系数增加2。由于增加的数字(代码中的rightOnesPattern )被使用了两次,因此错误传播了两次。该错误需要纠正。向右移动2个位置将校正结果。
该方案的俗称为s AMEň赭华氏度ØNE B的。
C++
#include
using namespace std;
typedef unsigned int uint_t;
// this function returns next higher number with same number of set bits as x.
uint_t snoob(uint_t x)
{
uint_t rightOne;
uint_t nextHigherOneBit;
uint_t rightOnesPattern;
uint_t next = 0;
if(x)
{
// right most set bit
rightOne = x & -(signed)x;
// reset the pattern and set next higher bit
// left part of x will be here
nextHigherOneBit = x + rightOne;
// nextHigherOneBit is now part [D] of the above explanation.
// isolate the pattern
rightOnesPattern = x ^ nextHigherOneBit;
// right adjust pattern
rightOnesPattern = (rightOnesPattern)/rightOne;
// correction factor
rightOnesPattern >>= 2;
// rightOnesPattern is now part [A] of the above explanation.
// integrate new pattern (Add [D] and [A])
next = nextHigherOneBit | rightOnesPattern;
}
return next;
}
int main()
{
int x = 156;
cout<<"Next higher number with same number of set bits is "<
Java
// Java Implementation on above approach
class GFG
{
// this function returns next higher
// number with same number of set bits as x.
static int snoob(int x)
{
int rightOne, nextHigherOneBit, rightOnesPattern, next = 0;
if(x > 0)
{
// right most set bit
rightOne = x & -x;
// reset the pattern and set next higher bit
// left part of x will be here
nextHigherOneBit = x + rightOne;
// nextHigherOneBit is now part [D] of the above explanation.
// isolate the pattern
rightOnesPattern = x ^ nextHigherOneBit;
// right adjust pattern
rightOnesPattern = (rightOnesPattern)/rightOne;
// correction factor
rightOnesPattern >>= 2;
// rightOnesPattern is now part [A] of the above explanation.
// integrate new pattern (Add [D] and [A])
next = nextHigherOneBit | rightOnesPattern;
}
return next;
}
// Driver code
public static void main (String[] args)
{
int x = 156;
System.out.println("Next higher number with same" +
"number of set bits is "+snoob(x));
}
}
// This code is contributed by mits
Python 3
# This function returns next
# higher number with same
# number of set bits as x.
def snoob(x):
next = 0
if(x):
# right most set bit
rightOne = x & -(x)
# reset the pattern and
# set next higher bit
# left part of x will
# be here
nextHigherOneBit = x + int(rightOne)
# nextHigherOneBit is
# now part [D] of the
# above explanation.
# isolate the pattern
rightOnesPattern = x ^ int(nextHigherOneBit)
# right adjust pattern
rightOnesPattern = (int(rightOnesPattern) /
int(rightOne))
# correction factor
rightOnesPattern = int(rightOnesPattern) >> 2
# rightOnesPattern is now part
# [A] of the above explanation.
# integrate new pattern
# (Add [D] and [A])
next = nextHigherOneBit | rightOnesPattern
return next
# Driver Code
x = 156
print("Next higher number with " +
"same number of set bits is",
snoob(x))
# This code is contributed by Smita
C#
// C# Implementation on above approach
using System;
class GFG
{
// this function returns next higher
// number with same number of set bits as x.
static int snoob(int x)
{
int rightOne, nextHigherOneBit,
rightOnesPattern, next = 0;
if(x > 0)
{
// right most set bit
rightOne = x & -x;
// reset the pattern and set next higher bit
// left part of x will be here
nextHigherOneBit = x + rightOne;
// nextHigherOneBit is now part [D]
// of the above explanation.
// isolate the pattern
rightOnesPattern = x ^ nextHigherOneBit;
// right adjust pattern
rightOnesPattern = (rightOnesPattern) / rightOne;
// correction factor
rightOnesPattern >>= 2;
// rightOnesPattern is now part [A]
// of the above explanation.
// integrate new pattern (Add [D] and [A])
next = nextHigherOneBit | rightOnesPattern;
}
return next;
}
// Driver code
static void Main()
{
int x = 156;
Console.WriteLine("Next higher number with same" +
"number of set bits is " + snoob(x));
}
}
// This code is contributed by mits
PHP
>= 2;
// rightOnesPattern is now part [A]
// of the above explanation.
// integrate new pattern (Add [D] and [A])
$next = $nextHigherOneBit | $rightOnesPattern;
}
return $next;
}
// Driver Code
$x = 156;
echo "Next higher number with same " .
"number of set bits is " . snoob($x);
// This code is contributed by ita_c
?>
Javascript
输出:
Next higher number with same number of set bits is 163
用法:查找/生成子集。
变化:
- 编写一个程序,找到一个比给定的数字小得多的数字,并且逻辑位数为1? (非常简单)
- 如何计算或生成给定集中可用的子集?
参考:
- 一个不错的演示。
- 沃伦(Warren)的Hackers Delight(一本精巧的短本,介绍各种位魔术算法,对于发烧友来说是必不可少的)
- Harbison和Steele撰写的CA参考手册(有关标准C的好书,您可以在此处访问本文的代码部分)。