2021.01.21 二进制中1的个数

今日题目:请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
image.png
image.png
image.png
提示:输入必须是长度为 32 的 二进制串 。

  • 思路:救命,这题好烦。写生气了。
    • 法一:暴力法。分为正数与负数进行处理。(想的太复杂了55555)时间复杂度为O(n),空间复杂度为O(1)
      • 正数:当n > 1时,对2取余,若为1,则count(计数器)++,最后再进行count ++。
      • 负数:令n=n的相反数,把n的二进制表示分为两部分,以最右边的一个1为分界线,进行两个阶段的处理。例:00001000,设置一个布尔值tag用来区分两个阶段,同时用一个length来记录位数。第一阶段:先对2取余,一直到n>1且余数为1的情况,修改tag的值进入第二阶段。第二阶段:依旧是对2取余,若余数为0则count(计数器)++。每算出一位,length就进行加1。最后length再进行加一,若n是奇数则进行count++,1的个数就是32 - length + count。
    • 法二:偷懒,直接调用Integer类中的bitCount()方法orz。
    • 法三:逐位判断。因为提示说把n当作无符号数进行处理,则采用无符号右移的方式。n & 1== 0(n的最后一位为0),n & 1 ==1(n的最后一位为1)。时间复杂度为O(logn),空间复杂度为O(1)。
    • 法四:大佬神了。设置一个计数器count用于记录1的数量,以n != 0为条件,令n = n & (n - 1); n & (n - 1)操作可以消掉n最右边的1。时间复杂度为O(M),M为1的个数,空间复杂度为O(1)。

注意:哈哈哈 n&(n-1) 还可以用来判断 n 是否是 2 的幂~

  • 自己的菜鸡代码: ```java // 法一 public class Solution { // you need to treat n as an unsigned value public int hammingWeight(int n) {
    1. // int 类型有4B,为32位,为有符号整数,所以要把十进制数转为二进制数再确定1的个数
    2. // count 用于统计1的个数
    3. int count = 0;
    4. // 正数
    5. //System.out.println(n);
    6. if(n > 0){
    7. while(n > 1){
    8. if(n % 2 == 1) ++count;
    9. n = n / 2;
    10. }
    11. ++count;
    12. }else if(n < 0){
    13. // 负数
    14. if(n == -2147483648) return 1;
    15. n = 0 - n;
    16. boolean tag = false;
    17. int length = 0;
    18. while(n > 1){
    19. ++length;
    20. if(!tag && n % 2 == 1) {
    21. ++count;
    22. tag = true;
    23. }
    24. if(tag && n % 2 == 0) ++count;
    25. n = n / 2;
    26. }
    27. if(!tag) ++count;
    28. ++length;
    29. count = 32 - length + count;
    30. }
    31. return count;
    } }

// 法二 public class Solution { // you need to treat n as an unsigned value public int hammingWeight(int n) { int res = 0; while(n != 0){ res += n & 1; n >>>= 1; } return res; } }

// 法三 public class Solution { // you need to treat n as an unsigned value public int hammingWeight(int n) { int res = 0; while(n != 0){ res += n & 1; n >>>= 1; } return res; } }

// 法四

  1. - 运行结果:
  2. 法一(左)、法二(右)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611207805440-317331f2-cbd4-4ab2-b412-1964fdaf932f.png#align=left&display=inline&height=238&margin=%5Bobject%20Object%5D&name=image.png&originHeight=466&originWidth=699&size=29554&status=done&style=none&width=357)![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611207908683-411e279f-889d-4fa7-860e-2b08eb6fa07b.png#align=left&display=inline&height=225&margin=%5Bobject%20Object%5D&name=image.png&originHeight=450&originWidth=684&size=28664&status=done&style=none&width=342)<br />法三(左)、法四(右)<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611211292012-0828c7d4-509b-4a65-bcd3-0040741fefd8.png#align=left&display=inline&height=291&margin=%5Bobject%20Object%5D&name=image.png&originHeight=494&originWidth=617&size=31458&status=done&style=none&width=363)![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611214819239-e7c0289f-af41-4f74-9f11-476440a6d75d.png#align=left&display=inline&height=227&margin=%5Bobject%20Object%5D&name=image.png&originHeight=454&originWidth=621&size=29254&status=done&style=none&width=310.5)
  3. <a name="WaXOw"></a>
  4. ### 2021.01.21 2的幂
  5. 今日题目:给定一个整数,编写一个函数来判断它是否是 2 的幂次方。<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611215181047-8adb7d7c-a42d-40f8-94ae-31ce2510d4d5.png#align=left&display=inline&height=151&margin=%5Bobject%20Object%5D&name=image.png&originHeight=152&originWidth=179&size=3076&status=done&style=none&width=178)![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611215193585-8ac6fb0e-0f0d-40a6-a70b-34569ffadb39.png#align=left&display=inline&height=148&margin=%5Bobject%20Object%5D&name=image.png&originHeight=156&originWidth=193&size=3398&status=done&style=none&width=183)![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611215207391-664e87b2-ef14-4b0e-a144-e922dd811d3a.png#align=left&display=inline&height=143&margin=%5Bobject%20Object%5D&name=image.png&originHeight=143&originWidth=191&size=2811&status=done&style=none&width=191)
  6. - 思路:利用上面问题中的 n & (n - 1),在n > 0时,若n2的幂,则n & (n - 1)的结果为0,否则不为0。(大佬太强悍了)
  7. - 自己的菜鸡代码:
  8. ```java
  9. class Solution {
  10. public boolean isPowerOfTwo(int n) {
  11. return n > 0 && (n & (n - 1)) == 0;
  12. }
  13. }
  • 运行结果:

image.png

2021.01.25 不用加减乘除做加法

今日题目:写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
image.png
提示:

  • a, b 均可能是负数或 0
  • 结果不会溢出 32 位整数

  • 思路:因为题目中明确说明不能用“+”、“-”、“*”、“/” 四则运算符号,所以很明显就是用位运算,用value来记录结果值,用 c 记录每一位运算的进位情况,用res_a、res_b记录a 与 b的每一位。这个问题有一些棘手的地方:

    1. 因为是逐位运算,所以需要记录已计算的位数:

因为不能用加法,所以不能使用普通的记录值,-2147483648在java中的存储形式为 80000000H,每计算完一位,就将count逻辑右移一位,当count == 0时代表已经运算完毕,直接将value返回就好。

  1. 如何记录每一位的运算值:
    • 运算过程:(1+2)0000……0001 + 0000……0010 6

初始化:
int value = 0; int c = 0;
int res_a = 0, res_b = 0;
int count = -2147483648;
循环条件:count != 0
先获得a、b当前位的值(a、b分别和 1 相与),
并将value右移一位
图中空白处默认为0
刚刚开始的时候: image.png
value右移一位之后此时res_a = 1,res_b = 0,c = 0;image.png
开始计算,分为 4 种情况:

  1. 1. res_a + res_b + c ==0c = 0; ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611568610640-355356c0-61e2-44e8-91ac-71a28852cab4.png#align=left&display=inline&height=36&margin=%5Bobject%20Object%5D&name=image.png&originHeight=72&originWidth=844&size=5014&status=done&style=none&width=422)
  2. 1. res_a + res_b + c ==1value = value | -2147483648c = 0; ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611568558857-7dedbeaf-8903-4a31-897f-f9e7a354d5c3.png#align=left&display=inline&height=37&margin=%5Bobject%20Object%5D&name=image.png&originHeight=73&originWidth=837&size=4585&status=done&style=none&width=418.5)
  3. 1. res_a + res_b + c ==2c = 1; ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611568610640-355356c0-61e2-44e8-91ac-71a28852cab4.png#align=left&display=inline&height=36&margin=%5Bobject%20Object%5D&name=image.png&originHeight=72&originWidth=844&size=5014&status=done&style=none&width=422)
  4. 1. res_a + res_b + c ==3value = value | -2147483648c = 1; ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1584832/1611568558857-7dedbeaf-8903-4a31-897f-f9e7a354d5c3.png#align=left&display=inline&height=37&margin=%5Bobject%20Object%5D&name=image.png&originHeight=73&originWidth=837&size=4585&status=done&style=none&width=418.5)

这一轮计算完毕之后,将a、b、count逻辑右移一位。
然后继续运算。image.png依次类推。

  1. - 时间复杂度:O(n),空间复杂度O(1)。
  • 自己的菜鸡代码:

    1. class Solution {
    2. public int add(int a, int b) {
    3. // 位运算,Java内部是以整数补码存储,模拟二进制运算(不能用 + 号 giao)
    4. int value = 0;
    5. int c = 0;
    6. int res_a = 0, res_b = 0;
    7. int count = -2147483648;
    8. // 循环停止的条件是 a 与 b 同时为 0
    9. while(count != 0){
    10. //获得a的最后一位
    11. res_a = a & 1;
    12. //获得b的最后一位
    13. res_b = b & 1;
    14. value >>>= 1;
    15. if(res_a == 1 && res_b == 1){
    16. if(c == 0){
    17. // // res_a + res_b + c == 2
    18. c = 1;
    19. }else{
    20. // res_a + res_b + c == 3
    21. value = value | -2147483648;
    22. c = 1;
    23. }
    24. }else if(res_a == 0 && res_b == 0){
    25. if(c == 1){
    26. // res_a + res_b + c == 1
    27. value = value | -2147483648;
    28. c = 0;
    29. }
    30. }else{
    31. if(c == 0){
    32. // res_a + res_b + c == 1
    33. value = value | -2147483648;
    34. c = 0;
    35. }else{
    36. // res_a + res_b + c == 2
    37. c = 1;
    38. }
    39. }
    40. a >>>= 1;
    41. b >>>= 1;
    42. count >>>= 1;
    43. }
    44. return value;
    45. }
    46. }
  • 运行结果:

image.png

2021.02.15 两数之和

今日题目:不使用运算符 + 和 - ,计算两整数 a 、b 之和。
image.pngimage.png

  • 思路:这题很明显就是使用位运算,跟上一题一样,但是看了大佬的思路发现有更简便的方法。异或操作可以得到两个数无进位的加法结果,与操作可以得到两个数的进位情况。

如:3+9 = 12
0011 & 1001 = 0001 0011 XOR 1001 = 1010
随后需要将无进位的加法结果加上进位结果,所以需将进位结果左移一位再相加。
循环结束的条件就是进位结果为0;

  • 自己的菜鸡代码:

    1. class Solution {
    2. public int getSum(int a, int b) {
    3. while(b != 0){
    4. // 得到进位结果
    5. int c = a & b;
    6. // 进位结果左移一位
    7. c = (c <<= 1);
    8. // 得到无进位的加法结果
    9. a = a^b;
    10. // 保存进位结果
    11. b = c;
    12. }
    13. return a;
    14. }
    15. }
  • 运行结果:

image.png