以下案例不做问题具体描述,详情参考《剑指Offer》题目10二进制中1的个数、题目40数组中只出现一次的数字、题目47不用加减乘除做加法。
案例一:题目10二进制中1的个数
//输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
class Solution {
public:
int NumberOf11(int n)
{
int count = 0;
/*
* 第一种解法:n与1做与运算,然后不断右移
*/
while (n)
{
if (n & 1)
count++;
n = n >> 1; //如果n是负数,右移后左边补“1”,将会陷入死循环
}
return count;
}
int NumberOf12(int n)
{
int count = 0;
/*
* 第二种解法:n与1做与运算,判断最低位是否为1;
* 1左移,n与2做与运算,判断次低位是否为1
*/
//long long tmp = 1;
unsigned int tmp = 1;
int whileCount = 0;
while (tmp)
{
whileCount++; //循环执行的次数和系统的整数二进制的位数相同
if (n & tmp)
count++;
char nTwo[65]; //观察一下n和tmp的二进制
char tmpTwo[65];
_itoa(n, nTwo, 2);
_itoa(tmp, tmpTwo, 2);
cout << "n:" << nTwo << ", tmp:" << tmpTwo << endl;
tmp = tmp << 1; //1、100、1000、1000
}
cout << whileCount << endl;
return count;
}
int NumberOf13(int n)
{
int count = 0;
/*
* 第三种解法:n & n-1
*/
while (n) //循环次数 = n中1的个数
{
++count;
n = n & (n - 1);
}
return count;
}
};
void main()
{
//函数名: itoa
//功 能 : 把一整数转换为字符串
//用 法 : char *itoa(int value, char *string, int radix);
int number = 8;
char string[25];
_itoa(number, string, 2); //_itoa_s ———— 第三个参数用于将数字转换成不同的进制(2、8、10、16)
printf("Integer = %d, String = %s\n", number, string);
cout << endl;
//移位基础
int i = 0x8000000f; //这里的0x8000000f为int型数据的补码形式
int j = i >> 3; //右移是算术移位,左端补齐的是符号位
int k = i << 3; //左移是逻辑移位,右端补0
char itwo[33];
_itoa(i, itwo, 2);
printf("i:十进制 = %d, 二进制 = %s\n", i, itwo);
char jtwo[33];
_itoa(j, jtwo, 2);
printf("j:十进制 = %d, 二进制 = %s\n", j, jtwo);
char ktwo[33];
_itoa(k, ktwo, 2);
printf("k:十进制 = %d, 二进制 = %s\n", k, ktwo);
printf("%d %x\n", i, i); //-2147483633 8000000f
printf("%d %x\n", j, j); //-268435455 f0000001
printf("%d %x\n", k, k); //30 1e
cout << endl;
Solution s;
cout << s.NumberOf13(8) << endl;
cout << s.NumberOf13(-8) << endl;
}
案例二:题目40数组中只出现一次的数字
//一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
class Solution {
public:
void FindNumsAppearOnce(vector<int> data, int* num1, int *num2) {
/*
*知识点1:异或运算性质:(1)A^B=b^A;(2)X^0=x;(3)X^X=0
*难点1:整个数组分成两个子数组:每个数组只包含一个只出现一次的数字,其他数字都成对出现
*/
if (data.size() < 2)
{
return;
}
int tmpOR = 0;
for (int i = 0; i < data.size(); i++)
{
tmpOR = tmpOR ^ data[i];
}
//所有数字异或运算,相同的数字抵消,最后的结果是num1, num2异或的结果
//tmpOR肯定有一位是1,所有数据根据此位上是否是1分成两个子数组
unsigned int indexOf1 = findFirstbitis1(tmpOR);
//划分子数组,并进行各自进行异或运算
*num1 = *num2 = 0;
for (int j = 0; j < data.size(); j++)
{
if (isBit1(data[j], indexOf1))
*num1 = *num1 ^ data[j];
else
*num2 = *num2 ^ data[j];
}
}
//寻找右边数第一位1
unsigned int findFirstbitis1(int num)
{
int indexOfBit = 0;
while ((num & 1) == 0 ) //&& (indexOfBit < 8 * sizeof(int))
{
num = num >> 1;
indexOfBit++;
}
return indexOfBit;
}
//判断num的indexBit位是否为1
bool isBit1(int num, unsigned int indexBit)
{
num = num >> indexBit;
return (num & 1);
}
};
案例三:题目47不用加减乘除做加法
//求两个整数之和,要求在函数体内不得使用 + 、- 、*、/ 四则运算符号。
class Solution {
public:
int Add(int num1, int num2)
{
int sum, carry;
do
{
sum = num1 ^ num2; //不考虑进位,对每一位相加。(0+0、1+1=0;0+1、1+0=1 =====》 异或运算)
carry = (num1 & num2) << 1; //两个数先进行与运算,再左移一位
num1 = sum;
num2 = carry;
} while (num2 != 0); //运算结束条件:不再产生进位
return num1;
}
};