day 17-18 算法:位運算,統計位1的個數,2的冪次方;比特位計數

1. 題目

  1. 編寫一個函數,輸入無符號整數,返回二進制表達式中的數字位數爲’1’的個數,也稱爲漢明重量:https://leetcode-cn.com/problems/number-of-1-bits/
  2. 給定一個整數,編寫一個函數欄判斷它是否是2的冪次方:https://leetcode-cn.com/problems/power-of-two/
  3. 比特位計數:給定一個非負整數num,對於0<=i<=num範圍中的每個數字i,計算其二進制數中的1的數目並將它們作爲數組返回:https://leetcode-cn.com/problems/counting-bits/

2. 基本知識

2.1 位運算介紹

計算機是用二進制存儲和計算的,直接使用二進制進行運算,那麼效率會高很多。

10進制轉換爲二進制:10進制的數除以2取餘,再用得到的商除以2再取餘,一直循環到商爲0,然後將餘數按高位到低位排列起來就是二進制數。
6的二進制:110

2.2 位運算常用的操作

  • & : 與,兩個位都爲1,結果才爲1
  • | : 或,兩個位都爲0,結果才爲0
  • ^ : 異或,兩個位相同爲0,相異爲1
  • ~ : 取反,0變1,1變0
  • << : 左移,各二進制位全部左移若干位,低位補0
  • : 右移,各二進制位全部右移若干位,無符號數,高位補0;有符號數,各編譯器處理方法不一,有的補符號位(算術右移),有的補0(邏輯右移)

2.3 位運算的應用

2.3.1 異或

x ^ 0 = x 和0做異或運算,x不變
x ^ 1s = ~x ,1s表示位數全爲1的數,任何數和1進行異或運算都是取反
x ^ (~x) = 1s
x ^ x = 0 因爲每個位數都一樣,所以得0

兩個數交換
常規寫法:

int temp = x;
x = y;
y = temp;

使用異或:

x = x ^ y; // ①
y = x ^ y; // ②
x = x ^ y; // ③

拆解一下(異或支持交換律和結合律的):

  1. ①是初始條件
  2. ②拆解爲:y = (x ^ y) ^ y = x^ (y ^ y) = x ^ 0 = x
  3. ③拆解爲:x = (x ^ y) ^ x = (x ^ x) ^ y = 0 ^ y = y

2,3,2 與運算

x = x &(x - 1) //清零最低位的1
x & -x // 可以得到最低位的1(並不一定是最後一位)

判斷奇偶

%2寫法:

x % 2  //結果爲1,則x是奇數,結果爲0,則x是偶數

與運算寫法:

x & 1  //結果爲1,則x是奇數,結果爲0,則x是偶數

與運算解法拆解一下,6&1=> 110&001,前面的位數不管是0還是1,和0做&運算都是0,則結果爲最後一位和1做&運算,得到如上的結果。

3. 算法題解

3.1 編寫一個函數,輸入無符號整數,返回二進制表達式中的數字位數爲’1’的個數,也稱爲漢明重量

解法1:判斷最後一位奇偶,然後左移一位,直到爲0
該解法時間複雜度爲O(1)(常數次循環),空間複雜度爲O(1)

private int hanmingWeight(int n) {
    int sum = 0;

    while (n != 0) {
        if ((n & 1) == 1) {
            sum++;
        }
        n <<= 1;
    }
    return sum;
}

解法2:通過x & (x-1)這個公式,可以把最後一位1置爲0,不斷循環直到n爲0

該解法時間複雜度和空間複雜度都爲O(1)

private int hanmingWeight(int n) {
    int sum = 0;

    while (n != 0) {
        n &= (n - 1);
        sum++;
    }
    return sum;
}

3.2 給定一個整數,編寫一個函數欄判斷它是否是2的冪次方

2的冪次方有一個特點,換成二進制時,所有的位數值只有一個是1,其他爲0,而x & (x-1)這個公式可以將最後一個1清零,則有以下的解法。

private boolean isPowerOfTwo(int n) {
    return n > 0 & (n & (n - 1)) == 0;
}

3.3 比特位計數

給定一個非負整數num,對於0<=i<=num範圍中的每個數字i,計算其二進制數中的1的數目並將它們作爲數組返回

解法1 :循環每個數,找到每個數中1的個數

使用了漢明重量的算法

private int[] countBits(int num) {
    int[] result = new int[num];
    for (int i = 0; i < num; i++) {
        int resultI = hanmingWeight(i);
        result[i] = resultI;
    }
    return result;
}

解法2:

還是用到這個公式:x & (x-1),這個公式可以將最後一個1清零,那麼x = x & (x-1) + 1,延伸出來就是 第i個數的1的個數爲:count【i】 = count【i & (i - 1)】 + 1(因爲i&*(i-1)只去掉最後一個1)

private int[] countBis(int num) {
    int[] result = new int[num];
    result[0] = 0;
    for (int i = 1; i < num; i++) {
        result[i] = result[i & (i - 1)] + 1;
    }
    return result;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章