我需要翻转一个整数的二进制表示中的所有位。已知:
10101
输出应该是:
01010
如果我要写一个像 int flipBits(int n);
这样的方法,使用整数进行按位运算来完成这个操作,需要使用哪个位运算符?我只想翻转数字中已经存在的位,而不是对整个 32 位整数进行翻转。
我需要翻转一个整数的二进制表示中的所有位。已知:
10101
输出应该是:
01010
如果我要写一个像 int flipBits(int n);
这样的方法,使用整数进行按位运算来完成这个操作,需要使用哪个位运算符?我只想翻转数字中已经存在的位,而不是对整个 32 位整数进行翻转。
~
一元运算符是按位取反操作符。如果您需要的位数比int
类型能存储的位数少,那么在运算后您需要使用&
进行掩码操作。
~
操作后,需要左移一位来得到 Java 或人眼所期望的结果。 - soMuchToLearnAndShare直接使用按位取反运算符~
即可。
int flipBits(int n) {
return ~n;
}
要使用k个最低有效位,则将其转换为正确的掩码。
(我假设您至少想要1个位,这就是掩码从1开始的原因)
int flipBits(int n, int k) {
int mask = 1;
for (int i = 1; i < k; ++i)
mask |= mask << 1;
return ~n & mask;
}
正如Lưu Vĩnh Phúc所建议的,可以使用(1 << k) - 1
来创建掩码而不是使用循环。
int flipBits2(int n, int k) {
int mask = (1 << k) - 1;
return ~n & mask;
}
~
时,我得到了一些疯狂的值。有没有办法让它只使用整数中实际使用的位数? - Naftuli Kayint
始终是32位(2的补码),无论所表示的数字大小如何。 - Reese Moore(1 << k) - 1
,而不是循环并设置每个位。 - phuclv有多种方法可以使用位运算翻转所有位。
x = ~x; // has been mentioned and the most obvious solution.
x = -x - 1; or x = -1 * (x + 1);
x ^= -1; or x = x ^ ~0;
由于目前只有一种解决方案能够给出“正确”的结果,而那个解决方案并不是很好(使用字符串来计算前导零?那会在我的梦中萦绕着我;)
所以,我们来看一个漂亮干净的解决方案,应该可以工作-虽然我没有彻底测试过,但你可以理解。实际上,Java没有无符号类型对于这种问题非常烦人,但它应该仍然相当有效(如果我可以这么说,比创建一个数字字符串要优雅得多)。
private static int invert(int x) {
if (x == 0) return 0; // edge case; otherwise returns -1 here
int nlz = nlz(x);
return ~x & (0xFFFFFFFF >>> nlz);
}
private static int nlz(int x) {
// Replace with whatever number leading zero algorithm you want - I can think
// of a whole list and this one here isn't that great (large immediates)
if (x < 0) return 0;
if (x == 0) return 32;
int n = 0;
if ((x & 0xFFFF0000) == 0) {
n += 16;
x <<= 16;
}
if ((x & 0xFF000000) == 0) {
n += 8;
x <<= 8;
}
if ((x & 0xF0000000) == 0) {
n += 4;
x <<= 4;
}
if ((x & 0xC0000000) == 0) {
n += 2;
x <<= 2;
}
if ((x & 0x80000000) == 0) {
n++;
}
return n;
}
/* inverts all bits of n, with a binary length of the return equal to the length of n
k is the number of bits in n, eg k=(int)Math.floor(Math.log(n)/Math.log(2))+1
if n is a BigInteger : k= n.bitLength();
*/
int flipBits2(int n, int k) {
int mask = (1 << k) - 1;
return n ^ mask;
}
int flippingBits(int n) {
return n ^ ((1 << 31) - 1);
}
Binary 10101 == Decimal 21
Flipped Binary 01010 == Decimal 10
一行代码(使用JavaScript编写 - 您可以将其转换为您喜欢的编程语言)
10 == ~21 & (1 << (Math.floor(Math.log2(21))+1)) - 1
解释:
10 == ~21 & mask
掩码
:用于过滤掉所有重要位之前的所有前导位(nBits - 详见下文)。
如何计算重要位数?
Math.floor(Math.log2(21))+1 => Returns how many significant bits are there (nBits)
例子:
0000000001
返回 1
0001000001
返回 7
0000010101
返回 5
(1 << nBits) - 1 => 1111111111.....nBits times = mask
import java.math.BigInteger;
import java.util.Scanner;
public class CodeRace1 {
public static void main(String[] s) {
long input;
BigInteger num,bits = new BigInteger("4294967295");
Scanner sc = new Scanner(System.in);
input = sc.nextInt();
sc.nextLine();
while (input-- > 0) {
num = new BigInteger(sc.nextLine().trim());
System.out.println(num.xor(bits));
}
}
}
BigInteger(String)
和Scanner.nextInt()
的官方文档链接。 - CosmicGiantint flipBits(int n){
String bitString = Integer.toBinaryString(n);
int i = 0;
while (bitString.charAt(i) != '1'){
i++;
}
bitString = bitString.substring(i, bitString.length());
for(i = 0; i < bitString.length(); i++){
if (bitString.charAt(i) == '0')
bitString.charAt(i) = '1';
else
bitString.charAt(i) = '0';
}
int result = 0, factor = 1;
for (int j = bitString.length()-1; j > -1; j--){
result += factor * bitString.charAt(j);
factor *= 2;
}
return result;
}
我现在没有设置Java环境来测试它,但这是一般的想法。基本上只需将数字转换为字符串,去掉前导零,翻转位并将其转换回数字即可。Integer类甚至可能有一些将字符串解析为二进制数的方法。我不知道问题需要如何解决,这可能不是最有效的方法,但它会产生正确的结果。
编辑:polygenlubricants对this question的回答也可能有所帮助
public static int findComplement(int num) {
return (~num & (Integer.highestOneBit(num) - 1));
}