题目链接
题目内容
给定一个正整数,输出它的补数。补数是对该数的二进制表示取反。
注意:
给定的整数保证在32位带符号整数的范围内。
你可以假定二进制数不包含前导零位。
示例 1:
输入: 5
输出: 2
解释: 5的二进制表示为101(没有前导零位),其补数为010。所以你需要输出2。
示例 2:
输入: 1
输出: 0
解释: 1的二进制表示为1(没有前导零位),其补数为0。所以你需要输出0。
这里先说一下我原先失败的思路:输入测试数据后,将其从十进制转换为二进制,再进入循环判断把各位数的0 1进行置换,求出其补数之后再进行进制转换变成十进制。
最后测试不同的原因也很简单——数值溢出。测试数据稍大一些,转换为二进制占用的空间就越大,这时即使用long int也无法保证存放。最好的方法是设置成字符数组来存放转换过后的二进制数。
通过代码:
int findComplement(int num) {
int comple = 0, i, j = 0, temp;
char result[32] = {0}; // int -- 4 Byte, 4 * 8 = 32 bits
temp = num;
if (num == 1)
return 0;
else {
while (temp) {
i = temp % 2;
result[j++] = i;
temp = temp / 2;
}
while (j > 0) {
i = result[--j];
if (i == 0)
i = 1;
else
i = 0;
comple = i * pow(2, j) + comple;
}
return comple;
}
}
其实这个程序最后的修改部分很考验一个人的基础,倘若能熟练使用数组,也便不会出现直接定义整型数字导致溢出的现象,而且使用字符数组也少了很多不必要的判定条件。
当然这道题的出题目的并不是考这个,它的目的应该是考验对移位,异或的熟练程度。
int findComplement(int num) {
int re = 0, i = 0;
while (num) {
re += ((num % 2) ^ 1) << i++; //所有位数左移
num >>= 1; //num的所有位数向右移一位
}
return re;
}
位移位运算符是将数据看成二进制数,对其进行向左或向右移动若干位的运算。位移位运算符分为左移和右移两种,均为双目运算符。第一运算对象是移位对象,第二个运算对象是所移的二进制位数。
左移: 数值溢出的话丢弃掉最高位,0补最低位
右移:最低位正数补0,负数补1,也就是汇编语言中的算术右移.同样当移动的位数超过类型的长度时,会取余数,然后移动余数个位.
在C中,左移是逻辑/算术左移(两者完全相同),右移是算术右移,会保持符号位不变。
移位其实可以专门写一篇博客了,但我了解和应用并不多,只是参考这别人的介绍大致写了一下规则。以后再碰到类型题可以整理一下。
参考文章:C语言的移位操作符