剑指 Offer 15. 二进制中1的个数
题目:
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1'
的个数。
题解1:
直接调用Integer.bitCount()
函数
public int hammingWeight(int n) {
return Integer.bitCount(n);
}
题解2(逐位判断):
1.若n&1=0,则证明最右一位是0;反之若n&1=1,则证明最后一位是1,则返回值+1;
2.使得n右移一位,继续与1进行&操作,注意: Java 中无符号右移为 “>>>”
public int hammingWeight(int n) {
int res = 0;
while (n!=0){
if ((n&1)==1) res++;
n>>>=1;//不是n>>=1 三个“>”号
}
return res;
}
剑指 Offer 65. 不用加减乘除做加法
题目:
写一个函数,求两个整数a
和b
之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
题解:
1.不要考虑a(i)、b(i)以及i-1位置是否进位三者的关系,会有很多种情况太复杂,换一种角度;
2.如下图所示,a(i)和b(i)是第i个位置a和b的值,假如二者均为1,则进一位之后落下0,进位的需要*2即执行左移操作;
3.n(i)
是异或操作,c(i+1)
是与操作,则a+b=n+c(比如把1+1 转换为2+0,进位就是左移);
4.通过不断的循环,使得a+b转换成0+d,返回d即可;
5.通过一个例子可以发现进位在求&
操作时会出现等于0的情况,因此循环结束的条件为进位为0。
public int add(int a, int b) {
while (b!=0){
int c = (a&b)<<1;//c是进位
a = a^b; //a是无进位和
b=c;//b是进位
}
return a;
}
剑指 Offer 56 - I. 数组中数字出现的次数
题目:
一个整型数组 nums
里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
题解:
1.两个相同数字的异或操作值为0,0和任何数字的异或操作的结果均为其本身。
2.假设出现1次的两个数字是a和b,则数组中的全部数取异或操作的结果即为a和b的异或操作的结果;
例如:假设数组中的数字为{4,4,3,3,2,1} ,则4和4取异或为0,3和3取异或为0,最后只剩下2和1;
3.由于a和b不相等,则异或操作的结果中肯定有1的存在,找到结果中任意一个1,假设是p,按照该位置对数组中的数字重新进行划分,即a带着所有第i位为1的数字,b带着所有第i位为0的数字(或者二者颠倒)
- 如果
nums[i]&p==0
,证明第i位为0,则被分到组1; - 如果
nums[i]&p==1
,证明第i位为1,则被分到组2; - 各个组内再次进行异或操作,得到的最终结果返回即可。
public int[] singleNumbers(int[] nums) {
//定义数组中全部数字的异或结果为xor
int xor = 0;
for (int n:nums){
xor=xor^n;
}
//在xor中自右向左查找1
int p = 1;
while ((p&xor)==0){
p=p<<1;
}
//定义两个最终的返回值
int res1=0,res2=0;
for (int n:nums){
//如果第i位为0,则为组1,组内进行异或
if ((n&p)==0){
res1 = res1^n;
}else //如果第i位为1,则为组2,组内进行异或
res2 = res2^n;
}
int[] res = {res1,res2};
return res;
}
剑指 Offer 56 - II. 数组中数字出现的次数
题目:
在一个数组 nums
中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
题解1:
1.如果在数组中取出某一个出现三次的数字,并不会影响最后的与操作的结果,因为a&a==a;但是如果取出数组中出现一次的数字则会影响最后的与操作的结果。
2.步骤:
- 对数组中所有的数字进行与操作,记作
and
; - 剔除数组中的某一个数字,将剩下的数字进行与操作,记为
and2
; - 如果
and
和and2
不相等,返回结果即可
3. 代码提交是错误的
错误原因: 数组中全部的数字取与操作最后的结果大概率是0,造成一些奇奇怪怪的结果
public static int singleNumber(int[] nums) {
//定义返回值res
int res = 0;
//定义nums数组中全部数字的与操作结果
int and = nums[0];
for (int i:nums){
and = and & i;
}
//假设num[n]为出现一次的数字
for (int n=0;n<nums.length;n++){
res = nums[n];
int and2 = Integer.MAX_VALUE;
for (int i=0;i<n;i++){
and2 = and2 & nums[i];
}
if (n!=nums.length-1){
for (int i= n+1;i<nums.length;i++){
and2 = and2 & nums[i];
}
}
if (and2!=and){
break;
}
}
return res;
}
题解2:
1.遍历将数组中的数出现的次数存储在map集合中;
2.遍历map,寻找出现次数为1的key值,返回结果。
public static int singleNumber(int[] nums) {
int res = 0;
Map<Integer,Integer> map = new HashMap<>();
//通过遍历将数组中的数出现的次数存储在map集合中
for (int i:nums){
if (!map.containsKey(i)){
map.put(i,1);
}else {
int times = map.get(i);
map.remove(i);
map.put(i,times+1);
}
}
//遍历map,寻找出现次数为1的key值,返回结果
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue()==1){
res = entry.getKey();
}
}
return res;
}
我昨晚好像睡着了哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈!!!