交替位二進制數詳解

想了解更多數據結構以及算法題,可以關注微信公衆號“數據結構和算法”,每天一題爲你精彩解答。也可以掃描下面的二維碼關注
在這裏插入圖片描述
給定一個正整數,檢查他是否爲交替位二進制數:換句話說,就是他的二進制數相鄰的兩個位數永不相等。
示例 1:

輸入: 5
輸出: True
解釋:
5的二進制數是: 101

示例 2:

輸入: 7
輸出: False
解釋:
7的二進制數是: 111

示例 3:

輸入: 11
輸出: False
解釋:
11的二進制數是: 1011

示例 4:

輸入: 10
輸出: True
解釋:
10的二進制數是: 1010

答案:

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

個數的二進制位如果是0和1交替,那麼把這個數往右移一位然後再和原來的數進行異或運算,就會讓他全部變爲1(注意這裏是忽略前面的0的,比如5在java語言中的二進制是32位,我們只考慮後面的101,不用考慮前面的29個0。)。我們來隨便舉個例子畫個圖看一下

在這裏插入圖片描述
所以他會把原來的位置上全部變爲1,然後我們再加1,讓他原來的位置全部變爲0,然後在和原來的自己進行與運算,判斷結果是否爲0。

2,加法實現

上面的異或運算我們還可以改爲加法運算,像下面這樣

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

3,逐個判斷

我們還可以使用最原始的方式,從右往左一個個判斷0和1是否是交替出現的,代碼也很簡單,我們來看下

 public boolean hasAlternatingBits(int n) {
     int pre = n & 1;
     for (int i = 1; i < 32; i++) {
         if ((1 << i) > n)
             break;
         int cur = (n >> i) & 1;
         if ((cur ^ pre) == 0)
             return false;
         pre = cur;
    }
    return true;
}

第7行如果等於0,說明要麼連續出現了0,要麼連續出現了1,直接返回false即可。當然第7行的判斷我們還可以再改一下,換一種思路

 public boolean hasAlternatingBits(int n) {
     int pre = n & 1;
     n >>>= 1;
     while (n != 0) {
         if ((n & 1) == pre)
             return false;
         pre = n & 1;
         n >>>= 1;
     }
    return true;
}

第5行如果成立,說明要麼連續出現了0,要麼連續出現了1,和上面很類似,不過實現方式上有些差別。或者我們還可以不使用任何臨時變量,像下面這樣每兩兩前後比較
4,前後兩兩比較

public boolean hasAlternatingBits(int n) {
    while (n != 0 && (n >>> 1) != 0) {
        if (((n & 1) ^ ((n >>> 1) & 1)) == 0)
            return false;
        n = n >>> 1;
    }
    return true;
}

或者我們還可以把它給爲遞歸的寫法

5,遞歸實現

public boolean hasAlternatingBits(int n) {
    return n < 3 || ((n % 2) != (n / 2 % 2)) && hasAlternatingBits(n / 2);
}

6,移兩位計算

再來想一下,前面我們把n往右移一位然後在與自己進行異或運算,我們能不能把n先往右移兩位在進行異或運算呢,其實也是可以的,我們來畫個圖分析一下
在這裏插入圖片描述
我們只需要計算異或的結果類似於10000…這種形式的就可以了,所以代碼很簡單,直接一行搞定

public static boolean hasAlternatingBits(int n) {
    return ((n ^= n >> 2) & (n - 1)) == 0;
}

我們來找幾個數據測試一下

    System.out.println("二進制0b111是不是0和1交替出現的:" + hasAlternatingBits(0b111));
    System.out.println("二進制0b101是不是0和1交替出現的:" + hasAlternatingBits(0b101));
    System.out.println("二進制0b1010101010是不是0和1交替出現的:" + hasAlternatingBits(0b1010101010));
    System.out.println("二進制0b1010101011是不是0和1交替出現的:" + hasAlternatingBits(0b1010101011));

看一下打印的結果

二進制0b111是不是01交替出現的:false
二進制0b101是不是01交替出現的:true
二進制0b1010101010是不是01交替出現的:true
二進制0b1010101011是不是01交替出現的:false

結果完全正確

7,乘以3計算

我們接着往下思考,如果n是0和1交替出現的,那麼會有兩種情況,一種是以0結尾的,比如101010,一種是以1結尾的,比如1010101,無論哪種情況我們把它乘以3會有一個奇怪的現象,因爲是0和1交替出現,0乘以3還是0,1乘以3是11(二進制),所以不會出現一直往前進位的問題,我們來看下代碼

public static boolean hasAlternatingBits(int n) {
    return ((n * 3) & (n * 3 + 1) & (n * 3 + 2)) == 0;
}

我們還是來找幾組數據來測試一下結果

    System.out.println("二進制0b111是不是0和1交替出現的:" + hasAlternatingBits(0b111000));
    System.out.println("二進制0b1010101010是不是0和1交替出現的:" + hasAlternatingBits(0b1010101010));
    System.out.println("二進制0b10101010101是不是0和1交替出現的:" + hasAlternatingBits(0b10101010101));
    System.out.println("二進制0b1010101011是不是0和1交替出現的:" + hasAlternatingBits(0b1010101011));

再來看一下打印結果

二進制0b111是不是01交替出現的:false
二進制0b1010101010是不是01交替出現的:true
二進制0b10101010101是不是01交替出現的:true
二進制0b1010101011是不是01交替出現的:false

結果完全在我們的預料之中。這種解法一般我們不太容易想到,但也不提倡使用,會有一些小的問題,因爲如果n比較小的話是沒問題的,如果n比較大的話,那麼n*3就會出現數字溢出,導致結果錯誤。如果想寫這種解法,最好先把n轉爲long類型就可以了。

8,使用java類庫

如果允許的話我們還以使用java類庫提供的方法先進行轉換,然後再進行判斷也是可以的,代碼比較簡單,我們來看下

public boolean hasAlternatingBits(int n) {
    String s = Integer.toBinaryString(n);
    for (int i = 0; i < s.length() - 1; i++) {
        if (s.charAt(i) == s.charAt(i + 1)) {
            return false;
        }
    }
    return true;
}

這種就非常好理解了,但對於二進制位的考察相對就弱了很多,或者我們還可以更簡潔一些

public static boolean hasAlternatingBits(int n) {
    String binary = Integer.toBinaryString(n);
    return !binary.contains("00") && !binary.contains("11");
}

9,總結

這道題難度不大,其實解法還是挺多的,主要考察的是對二進制位的熟練使用,如果上面的所有解題思路都能掌握,代碼也都能看的懂,那麼對二進制位的操作也算是比較熟練的了,但遠達不到精通,因爲關於二進制位運算的技巧還是非常非常多的,不是這一篇文字就能講的清楚的,後續也會有一系列對二進制位運算的介紹。

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