力扣算法做题日记之《位运算》01


以下算法题均来自leetCode题库 https://leetcode-cn.com/
本篇难度为简单

1.将数字变成 0 的操作次数

给你一个非负整数 num ,请你返回将它变成 0 所需要的步数。 如果当前数字是偶数,你需要把它除以 2 ;否则,减去 1 。

class Solution {
       //正数变成0的步骤数 ,偶数除以2,奇数减去1
    public int numberOfSteps (int number) {
        if (number == 0) return 0;
        return zeroNextValue(number, 0);
    }

    //二进制末尾是1的便是奇数
    private int zeroNextValue(int number, int step) {
        if (number == 0) return step;
        if ((number & 1) != 0) {
            step++;
            return zeroNextValue(number - 1, step);
        } else {
            step++;
            return zeroNextValue(number >> 1, step);
        }
    }
}

思路:二进制末尾为1的是奇数,为0的是偶数

2.二进制链表转整数

给你一个单链表的引用结点 head。链表中每个结点的值不是 0 就是 1。已知此链表是一个整数数字的二进制表示形式。
请你返回该链表所表示数字的 十进制值 。

// Definition for singly-linked list.
public class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
            val = x;
        }
 }

class Solution {
    public int getDecimalValue(ListNode head) {
       int val = head.val;
        while (head.next != null) {
            head = head.next;
            //左移一位相当于乘以2,下一位有1的直接或运算添加到二进制里
            val = head.val == 0 ? val << 1 : (val << 1) | 1;
        }
        return val;
    }
}

思路:构造链表同结构的二进制表示数

3.二进制中1的个数

请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

public class Solution {
    //我这按32位去计算二进制,应该没问题吧
    public int hammingWeight(int number) {
        int count = 0;
        for (int i = 0; i < 32; i++) {
            if ((number & 1 << i ) != 0) count++;
        }
        return count; 
    }
}

思路:对整数的每个位置都进行是否是1的判断

4.最大数值

编写一个方法,找出两个数字a和b中最大的那一个。不得使用if-else或其他比较运算符。

public class Solution {
     public int maximum(int a, int b) {
        //等于1是负数,即a<b;反之是a>b ,可能涉及两个正负最大值相减,超过int的最大范围
        //取符号位进行判断,long是64位,int是32位
        int val = ((int)(((long)a - (long)b) >> 63)) & 1;
        return a + (b - a) * val;
    }
}

思路:取差值,根据符号位判断大小值

5.数字的补数

给定一个正整数,输出它的补数。补数是对该数的二进制表示取反。

 public int findComplement(int num) {
         int origin = num;
        int val = 0;
        //一直往右位移,直到0为止,可以得出该数的二进制长度
        //构建一个等长的全1的二进制,进行异或运算
        while (num > 0) {
            num = num >> 1;
            val = val == 0 ? 1 : (val << 1) | 1;
        }
        return origin ^ val;
    }

思路:查找整数的为1的最高位,与同长度的全1二进制进行异或运算

6. 配对交换

配对交换。编写程序,交换某个整数的奇数位和偶数位,尽量使用较少的指令(也就是说,位0与位1交换,位2与位3交换,以此类推)

	  //10101010101010101010101010101010 = 0xaaaaaaaa
      //01010101010101010101010101010101 = 0x55555555
      public int exchangeBits(int num) {
        return (num << 1 & 0xaaaaaaaa) | (num >> 1& 0x55555555);
      }

思路:左右分别位移一位,最后的结果叠加

7.根据数字二进制下 1 的数目排序

给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。
如果存在多个数字二进制中 1 的数目相同,则必须将它们按照数值大小升序排列。
请你返回排序后的数组。

 public int[] sortByBits(int[] arr) {
        Integer integers[] = new Integer[arr.length];
        for (int i = 0; i < arr.length; i++) {
            integers[i] = new Integer(arr[i]);
        }
        Arrays.sort(integers, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                int bitCount1 = Integer.bitCount(o1);
                int bitCount2 = Integer.bitCount(o2);
                if (bitCount1 == bitCount2) {
                    return o1 - o2;
                }
                return bitCount1 - bitCount2;
            }
        });

        int[] result = new int[integers.length];
        for (int i = 0; i < integers.length; i++) {
            result[i] = integers[i].intValue();
        }
        return result;
    }

思路:使用比较器进行比较
Integer.bitCount() 方法返回的是二进制1的个数

8.只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

public int singleNumber(int[] nums) {
        int result = 0;
        for (int item : nums) {
            result ^= item;
        }
        return result;
    }

思路:异或运算和参与运算的两个数位置无关;
任何数和0异或等于该数本身;
两个相同数字异或运算等于0

9.找不同

给定两个字符串 s 和 t,它们只包含小写字母。
字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。
请找出在 t 中被添加的字母。

   public char findTheDifference(String s, String t) {
        char res = 0 ;
        char[] chars = s.toCharArray();
        char[] chart = t.toCharArray();
        for (char item : chart) {
            res ^= item;
        }
        for (char item : chars) {
            res ^= item;
        }
        return  res;
    }

思路:和题8的思路一样,异或两个相同的数等于0,最终剩下的就是多出来的

10.缺失的数字

给定一个包含 0, 1, 2, …, n 中 n 个数的序列,找出 0 … n 中没有出现在序列中的那个数。

 public int missingNumber(int[] nums) {
        int result = 0;
        for (int i = 0; i < nums.length; i++) {
            result = result ^ nums[i] ^ i;
        }
        return result^nums.length;
    }

思路:同上

11.交替位二进制数

给定一个正整数,检查他是否为交替位二进制数:换句话说,就是他的二进制数相邻的两个位数永不相等。

 public boolean hasAlternatingBits(int n) {
      int temp = n ^ (n >> 1);
      return (temp & (temp + 1)) == 0;
}

思路:交替位合并如果是正确的会组成全1的二进制

12.颠倒二进制位

颠倒给定的 32 位无符号整数的二进制位。

 public int reverseBits(int n) {
        int result = 0;
        for (int i = 0; i < 32; i++) {
            int last = n & 1;
            result = result << 1 | last;
            n = n >>> 1;
        }
        return result;
    }

思路:逆向位移输出

13.两整数之和

不使用运算符 + 和 - ​​​​​​​,计算两整数 ​​​​​​​a 、b ​​​​​​​之和。

 public int getSum(int a, int b) {
 	if (b == 0) return a;
        int temp = (a & b) << 1;   //算出所有需要进行进位+1的位置
        int resultTemp = a ^ b;
        return getSum(resultTemp, temp);
    }

思路:算出进位的位置,循环递归至没有进位为止

14.整数转换

整数转换。编写一个函数,确定需要改变几个位才能将整数A转成整数B。

public int convertInteger(int A, int B) {
  	    int count = 0;
        for (int i = 0; i < 32; i++) {
            if (((1 & A) ^ (1 & B)) == 1) count++;
            A = A >> 1;
            B = B >> 1;
        }
        return count;
    }

思路:遍历比较每一个位置的差异

15.4的幂

给定一个整数 (32 位有符号整数),请编写一个函数来判断它是否是 4 的幂次方。

   public boolean isPowerOfFour(int num) {
    if (num == 1) return true;
        if (num < 0 || (num & (num - 1)) != 0) return false;
        return (num & 0x55555555) != 0;
    }

思路:4的二进制是100,往前推10000,1000000也都是4的幂,就是除末尾外奇数位是1,且只有一位是1的二进制数都是4的幂,同时要算上4的0次幂1
4-1=3 = 011 , 16-1=15=01111,64-1=63=0111111

16.2的幂

给定一个整数,编写一个函数来判断它是否是 2 的幂次方。

 public boolean isPowerOfTwo(int num) {
            if (num <= 0 || (num & (num - 1)) != 0) return false;
        return (num & 1) == 0 || num == 1;
    }

思路:同上题,只是2的幂是除末尾外只有一位是1的二进制数

17.翻转数位

给定一个32位整数 num,你可以将一个数位从0变为1。请编写一个程序,找出你能够获得的最长的一串1的长度。

   public int reverseBits(int num) {
        int preCount = 0;
        int tempCount = 0;
        int result = 0;

        for (int i = 0; i < 32; i++) {
            if ((num & 1<< i) != 0) {
                preCount++;
            } else {
                result = Math.max(result, preCount + tempCount + 1);
                tempCount = preCount;
                preCount = 0;
            }
        }
        return Math.max(result, preCount + tempCount + 1);
    }

思路:
1.统计1的连续个数
2.遇到第一个不为1的二进制位时,保存上次的值,并把之前的值清空;同时计算此时的最大长度

18.数字转换为十六进制数

给定一个整数,编写一个算法将这个数转换为十六进制数。对于负整数,我们通常使用 补码运算 方法。
注意:
1.十六进制中所有字母(a-f)都必须是小写。
2.十六进制字符串中不能包含多余的前导零。如果要转化的数为0,那么以单个字符’0’来表示;对于其他情况,十六进制字符串中的第一个字符将不会是0字符。
3.给定的数确保在32位有符号整数范围内。
4.不能使用任何由库提供的将数字直接转换或格式化

  public String toHex(int num) {
   if (num == 0) return "0";
        int compare = 0xf;  //0xf
        char regex[] = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        StringBuilder sb = new StringBuilder();
        while (num != 0 && sb.length() < 8) {
            int temp = num & compare;
            sb.append(regex[temp]);
            num >>= 4;
        }
        return sb.reverse().toString();

    }

思路:二进制4位对应16进制的一位

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章