力扣算法做題日記之《位運算》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進制的一位

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