藍橋杯——想不到的位運算

Meteor發表於2022-12-31

一、前言

  • 筆者準備參加藍橋杯,所以再次記錄自己的學習心得。
  • 我會將自己的演算法學習之路用部落格進行記錄,並將學習思想進行分享。
  • 希望大家如果看文章的話,可以認真閱讀題目,並進行思考。
  • 希望和大家一起共同成長

二、奇妙的異或

1-1000這1000個數放在含有1001個元素的陣列中,只有唯一的一個元素值重複,其它均只出現一次。每個陣列元素只能訪問一次,設計一個演算法,將它找出來;不用輔助儲存空間,能否設計一個演算法實現?

前置知識:

  • 一個數與本身進行異或,結果為0。A ^ A = 0
  • 任何數與零進行異或,結果為本身。 B ^ 0 = B

演算法思想:

  • 透過閱讀題目,我們可以利用異或性值,將1——1000這組資料複製一份,與原先的這組數進行異或,那麼我們重複的元素就會出現3次,而其他元素只出現兩次。
  • 所以我們可以得出最後的結果

// A ^ A = 0
// B ^ 0 = B
public class 唯一成對的數 {
    public static void main(String[] args) {
        int N = 101;
        int[] arr = new int[N];
        for(int i = 0; i < arr.length-1; i++) {
            arr[i] = i+1;
        }
        // 最後一個隨機數
        arr[arr.length-1] = new Random().nextInt(N);
        // 隨機下標
        int index = new Random().nextInt(N);
        // 隨機交換
        Utils.swap(arr, index, arr.length-1);
        System.out.println(Arrays.toString(arr));

        int res = 0;
        // 讓 res 與 1..100進行異或運算
        for(int i = 1; i <= N-1; i++) {
            res = res ^ i;
        }
        // 讓 1..100和多的一位數,與res進行異或,當兩個1..100進行異或時為0,所以答案就是剩下的最後一個值
        for(int i = 0; i < N; i++) {
            res = res ^ arr[i];
        }
        System.out.println(res);
    }
}

三、奇妙的運算

請實現一個函式,輸入一個整數,輸出該數二進位制表示中1的個數。
例如9的二進位制1001,有2個1

前置知識:

  • 與運算 1 & 1 = 1、1 & 0=0
  • 移位

演算法思想————解法一:

  • 我們可以讓該數與1從右至左進行與運算。這樣如果結果為1,那麼就是1,我們在進行判斷是否相等。
  • 每一次都需要將我們的1左移一位,也相當於對該二進位制數進行掃描
public class 二進位制1的個數 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        System.out.println(Integer.toString(N,2));

        int count = 0;
        // 讓1移位,與二進位制每一個數進行 與運算
        for (int i = 0; i < 32; i++) {
            if((N & (1 << i)) == (1 << i)) {
                count++;
            }
        }
        System.out.println(count);
    }
}

演算法思想————解法二:

  • 可以採用該數-1操作,然後與原來的數進行與運算,這樣我們可以消除最右邊的1,直接把1全部消掉,結果為0為止。
        // 因為二進位制-1後和 原先的值進行 與運算,會消除最右邊的1
        System.out.println("解法二-----------------");
        count = 0;
        while(N!=0) {
            N = (N-1)&N;
            count++;
        }
        System.out.println(count);

四、簡單的程式碼

用一條語句判斷一個整數是不是2的整數次方。

演算法思想:

  • 我們知道2的整數次方的二進位制,應該是隻含有一個1的
  • 所以本題我們就可以變解為求二進位制中是否存在一個1
  • 利用我們上面所學的求1的個數,那麼我們很快就可以解決。
if( ((N-1)&N)) == 0) return true;

五、複雜的運算

陣列中只有一個數出現了1次,其他的數都出現了k次,請輸出只出現了1次的數。

前置知識:

  • 2個相同的2進位制數做不進位加法,結果為0
  • 10個相同的10進位制數做不進位加法,結果為0
  • k個相同的k進位制數做不進位加法,結果為0

演算法思想:

  • 所以本題我們可以將出現k次的數,轉換為k進位制,然後進行加法運算。
  • 我們還需要將數字進行翻轉,這樣才能夠保證我們在做加法運算時,最低位是對齊的。
  • 其實我們可以採用雜湊錶速速解決戰鬥,但是我們學習的是位運算的思想。

六、結尾

  • 對於藍橋杯位運算知識內容就總結這麼多,若想深入學習等待後續更新。
  • 我將會繼續更新關於藍橋杯方向的學習知識,感興趣的小夥伴可以關注一下。
  • 文章寫得比較走心,用了很長時間,絕對不是copy過來的!
  • 尊重每一位學習知識的人,同時也尊重每一位分享知識的人。
  • ?你的點贊與關注,是我努力前行的無限動力。?