1. 程式人生 > >筆試面試中常見的位運算用法

筆試面試中常見的位運算用法

   本文是準備找工作過程中關於位運算的一些積累和記錄的整理。注意:部分位運算的處理結果依賴於變數所屬型別的字長,使用時請結合具體環境修改。

1.XOR應用

性質:滿足交換率、結合律,一個數與其自身異或結果為0。

(1)不用中間變數,交換兩數

a = a^b;
b = b^a; //b = b^(a^b),thus b becomes the earlier a
a = a^b; //a = (a^b)^a,thus a becomes the earlier b

擴充套件:不用異或,同樣也能不用中間變數,交換兩數

a = a - b;
b = a + b; // b = (a - b)+ b, thus b becomes the earlier a
a = b - a; // a = a - (a - b), thus a becomes the earlier b

但是這種方式引入了一個陷阱,如果a是一個很大的正數而b是一個很小的負數,那麼a-b就會溢位。雖然在b=a+b時可能會通過再一次溢位從而獲得真實的a的值,不推薦這種利用未定義行為的解法

如何理解這種解法?其實第一行是a=a-b還是a=a+b再或者是a=a*b都可以,對應地在第二行把b通過這個式子和b本身的運算求出a即可,再在第三行利用ab的組合值以及原先的a求解b。明顯地,使用*比+或-更容易溢位。理解後,完全不必死記硬背這三個式子,看成是解方程就不難了。

(2)尋找只出現1次的一個數,其他數出現偶數次(或尋找唯一一個出現奇數次的數,其他數出現偶數次)

解法:全部數做XOR,最後的結果就是要找的數。

擴充套件:尋找出現奇數次的數,其他不必尋找的數只出現偶數次。 

常見的面試題擴充套件,思路還是原來的思路,先全部XOR一遍,在獲得的結果上,對每一位為1(即可能有兩個不同的數,二進位制標識中該位不同)進行分組,構造出所有待找出的數。

這麼概括很抽象,看一道具體的筆試題吧,通過解題就容易理解了。

(小米2013校招筆試題)一個數組裡,除了三個數是唯一出現的,其餘的都出現偶數個,找出這三個數中的任一個。比如陣列元素為【1, 2,4,5,6,4,2】,只有1,5,6這三個數字是唯一出現的,我們只需要輸出1,5,6中的一個就行。

(3)NIM遊戲的狀態分析

  請參考《程式設計之美》1.12 NIM(2) “拈”遊戲分析。其核心是,兩種完全不同的狀態(安全狀態和不安全狀態)的XOR值恰為0和1。

2.加法,不用+-*/做加法(《劍指Offer》面試題47

迭代版本(《劍指Offer》面試題47)

int Add(int num1,int num2)
{
    int sum,carry;
    do {
        sum = num1^num2;
        carry= (num1 & num2)<<1;
        num1 = sum;
        num2 = carry;
    } while (num2!=0)
    return num1;
}

遞迴版本(CareerCup 20.1)

int add_no_arithm(int num1,int num2)
{
    if(num2 == 0)
        return num1;
    int sum = a^ b;
    int carry = (a&b)<<1;
    return add_no_arithm(sum,carry);
}

3.求兩數的平均數 不用-、*、/求兩數的平均數 

似乎是出自《程式設計師面試寶典》,但是我在第三版第12章沒找到原題。用下面的程式碼就能“神奇地”獲得兩個整型的平均值

int  average(int x,int y)
{
    return ( (x&y) + ( (x^y)>>1 ) );
}

4.不用*和/做除法(《演算法設計手冊》面試題1-28)

  縱觀第2、3、4條可以發現,如果問題限制不允許使用某種四則運算子以及%,就可以在位運算上打主意了。

5.二進位制中1的個數

  不要覺得很trick,這是K&R提到過的。值得注意的是,如果使用C實現,為了避免實現定義不同造成的結果不同,需要把該變數轉化為無符號型。

int bitcount(unsigned x)
{
    int b;
    for(b=0;x|=0;x>>=1)
        if(x&01)
            b++;
    return b;
}

  事實上K&R習題2-9提到了一種更快的演算法:

int bitcount(unsigned x)
{
    int b;
    for(b=0;x!=0;x&= x-1)
        b++;
    return b;
}

6.從無符號型x的第p位開始,取n位(K&R)

//最低位是第0位
unsigned getbits(unsigned x,int p, int n)
{
    return (x>>(p+1-n)) & ~(~0<<n);
}

7.利用同餘的性質和位運算加速的輾轉相減求最大公約數法(《C語言參考手冊》第七章)

unsigned binary_gcd(unsigned x, unsigned y)
{
    unsigned temp;
    unsigned common_power_of_two = 0;
    if(x==0)
        return 0;
    if(y==0)
        return 0;

    /*find the largest power of two
    that divides both x and y*/
    while(((x|y)&1)==0) {
        x >>= 1;
        y >>= 1;
        ++common_power_of_two;
    }
    while((x &1) == 0)
        x >>= 1;
    while(y) {
        /*x is odd and y is nonzero here*/
        while((y&1)==0)
            y >>= 1;
        /*x and y are odd here*/
        temp = y;
        if (x>y)
            y = x - y;
        else
            y = y-x;
        x = temp;
        /*Now x has the old value of y,which is odd.
         y is even,because it is the difference of 
        two odd numbers therefore it will be right-shifted
        at least once on the next iteration.*/
    }
    return (x<<common_power_of_two);
}

8.不用大於小於號,求兩數較大值(CareerCup 19.4)

int getMax(int a,int b)
{
    int c = a - b;
    int k = (c>>31)&0x1;
    int max = a-k*c;
    return max;
}

   在不允許使用>、<以及任何判斷語句時,使用移位判斷一個數的正負性是常用技巧,如《深入理解計算機系統》2.3.7節習題2.42中求補碼對給定2的冪的商的解法。這個問題以及求解涉及到補碼的表示和運算的知識,在此不進行詳述,有興趣的讀者可以自行查閱。

9.實現位向量

10.其他

相關推薦

筆試面試常見運算用法

   本文是準備找工作過程中關於位運算的一些積累和記錄的整理。注意:部分位運算的處理結果依賴於變數所屬型別的字長,使用時請結合具體環境修改。 1.XOR應用 性質:滿足交換率、結合律,一個數與其自身異或結果為0。 (1)不用中間變數,交換兩數 a = a^b; b = b^a; //b =

java 演算法題 - 面試常見操作演算法題

前言 上一篇部落格 聊一聊 Android 中巧妙的位操作 中,我們講解了 java 中常用的位運算及常用應用場景,今天,讓我們一起來看一下,面試中常見的位操作的演算法題。 兩個只出現一次的數字 【題目描述】一個整型數組裡除了兩個數字之外,其他的數字都出現了兩次。請寫程

程式設計運算用法總結

位運算應用口訣清零取反要用與,某位置一可用或 若要取反和交換,輕輕鬆鬆用異或 移位運算 要點 1 它們都是雙目運算子,兩個運算分量都是整形,結果也是整形。          2 "<

Java運算

post 得出 進制數 運算 運算符 ring 位運算 邏輯 異或 (轉載聲明:   出處:http://blog.csdn.net/vebasan/article/details/6193916   作者:vebasan  ) 位運算符主要針對二進制,它包括了:“與”、

運算和enum運算

bsp AR 分享 lin audition tis ati com pre 1、位邏輯非運算   ~ 位邏輯非運算是單目的,只有一個運算對象。位邏輯非運算按位對運算對象的值進行非運算,即:如果某一位等於0,就將其轉變為1;如果某一位等於1,就將其轉變為0。 比如,對二

C語言結構體冒號(域)用法

位域出現的原因是由於某些資訊的儲存表示只需要幾個bit位就可以表示而不需要一個完整的位元組,同時也是為了節省儲存空間和方便處理。   typedef struct  bit_struct {     int &n

Python 運算(部分)

真值表: >>> 1 & 1 1 >>> 1 & 0 0 >>> 0 & 1 0 >>> 0 & 0 0 >>> 1 | 1 1 >>> 1 |

面試常見的陣列的操作:遍歷,最值,反轉,氣泡排序,二分查詢(附程式碼)

陣列:儲存同一種資料型別的多個元素的容器;陣列中的索引從0開始,最大編號是陣列的長度-1(減1); 下面給大家列出陣列常見的幾種操作:     A 遍歷   /** * 遍歷 */ public static void printArray(int

java運算總結

轉自:https://www.cnblogs.com/liaopeng/p/8436155.html 1.^(亦或運算) ,針對二進位制,相同的為0,不同的為1 public static void main(String[] args) { System.out.println

js運算

不變 應該 困難 ring 比較 裝逼 個數 exp symbol 我們可能很少在編程中用位運算,如果沒深入學習,可能也很難理解。平時的數值運算,其實是要先轉換成二進制再進行運算的,而位運算就是直接進行二進制運算,所以位運算的執行效率肯定是更高的。下面通過一些實例來加深對位

那些年,面試常見的資料結構基礎和演算法題(下)

前言 這是 資料結構和演算法面試題系列的下半部分,這部分主要是演算法類 包括二分查詢、排序演算法、遞迴演算法、隨機演算法、揹包問題、數字問題等演算法相關內容。本系列完整程式碼在 github 建了個倉庫,所有程式碼都重新整理和做了一些基本的測試,程式碼倉庫地址在這裡: shishujuan/dsalg

java運算

由於位運算是二進位制運算,不要與一些八進位制數搞混,java中二進位制數沒有具體的表示方法。 public class BitMath{     public static void main(String[] args){         System.out.println

面試常見JS開發測試題

在前端很少有機會接觸到演算法,大多都互動性的操作,然而從各大公司面試來看,演算法依舊是考察的一方面。下面這篇文章就給大家總結了在前端JS面試中常見的測試題問題,有需要的朋友們可以參考借鑑,下面來一起看看吧。 前言 學習資料結構與演算法對於工程師去理解和分析問題都

連結串列專題——面試常見的連結串列問題

宣告:連結串列定義如下: //Java: class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } } //C++: typedef struct

程式設計師面試常見的雜湊表,到底是什麼?

作者 | 倪升武責編 | 胡巍巍我所寫的這些資料結構,都是比較經典的,也是面試中經常會出現的,這

#Java面試常見的11道題,你會了幾道?

大家在平常面試java的過程中都會遇到哪些難題呢?還有一些即將去面試java的童鞋們,你們想知道技術面試中會涉及到哪些點嗎? 如果有想學習java的程式設計師,可來我們的java學習扣qun:943111692,免費送java的視訊教程噢!我整理了一份適合18年學習的java乾貨,送給每

面試常見的字串庫函式程式設計

下面對一些常見的關於字元的庫函式進行實現,這些也是通常面試中所問的一些問題,需要注意的是有些看起來很簡單,但是一定要考慮一些邊界條件,否則很容易出錯. strcpy實現 char* strcpy(char* dst,const char* src){

校招面試常見的 MySQL 考察難點和熱點

基本架構 MySQL是典型的三層架構模式,在平常使用中對MySQL問題排查和優化,也應該針對具體問題,從對應的層解決問題 服務層:經典的C/S架構,主要是處理連線和安全驗證。 核心層:處理MySQL核心業務。 查詢分析,優化,快取和內建函式 。 內建的檢視,儲存過程,觸發器。 儲存引擎層:儲存引擎

嵌入式面試常見的問答題(執行緒程序、TCP等)

以下內容源於網路資料的學習整理,如有侵權,請告知刪除。 一、執行緒、程序的區別聯絡 個人理解:程序相當於一個執行中的程式,執行緒相當於程式中的某些函式。(實際程式設計也是如此) (1)這些函式都有獨立的執行入口、順序執行序列、出口。 (2)但這些函式不能獨立存

c++運算相關規律總結和口訣

位運算應用口訣清零取反要用與,某位置一可用或若要取反和交換,輕輕鬆鬆用異或 左移與右移--<<與>> a<<n <=> a*(2^n)  例如:a<<1 <=> a*2 a>>n <=