位運算使用技巧及巧解算法題

位運算使用技巧及巧解算法題

位運算

簡單的複習一下基本的位運算,這些使用技巧在下面都有用到。算法

// 按位與 & , 雙1得1, 其餘都得0,使用:好比設置某些位爲0,或者取某些位
// 按位或 | , 單1便可得1, 只有雙0才得0,使用:好比設置某些位爲1
// 異或 ^ , 相同則爲0,相反則爲1,即 10相碰得1,使用:好比取某些位的相反位

//下面這四個通常用來構造某些特殊的二進制數
// 按位取反 ~  很簡單,取反便可
// 左移 <<  把數向左移,右邊空出來的補0
// (無符號數)邏輯右移 >>   把數往右移,左邊空出來的補0,注意在C中只有無符號數才如此
// (有符號數)算術右移 >>    把數往右移,左邊空出來的補符號位,即正數補0,負數補1,有符號數執行的是算術運算
// 在其餘語言中可能有不一樣,好比Java中算術右移和邏輯右移就是不一樣的運算符: >>和>>>

簡單技巧

  1. 判斷整型的奇偶
if (x & 1)
       // 奇數
   else
       // 偶數
  1. 將一個數符號取反,即取相反數
int x;
x = ~x+1; //相反數
  1. 判斷第n位是否設置爲1
if (x & (1 << n))
       // 是
   else
       // 否
  1. 將第n位設置爲1
x = x | (1 << n);
  1. 將第n位設置爲0
x = x & ~ (1 << n);
  1. 將第n位取反
x = x ^ (1 << n);
  1. 【】將最右邊的1設爲0
x = x & (x-1);

【重要技巧】便可獲得比當前數二進位少1的數(且數值恰比當前數小)數組

  1. 設置第n到m位爲1(最左邊爲第0位)如下皆利用宏來實現
#define SETBITS1(x, n, m) (x) | ((~(0U)<<(sizeof(x)-(m-n+1)))>>n)

【注】:((~(0U)<<(sizeof(x)-(m-n+1)))>>n)是獲得第n位到第m位爲1,其餘位爲0,如00...000111111110000000...的形式函數

  1. 設置第n到m位爲0
#define SETBITS0(x, n, m) (x) & ~((~(0U)<<(sizeof(x)-(m-n+1)))>>n)
  1. 取第n到m位
#define GETBITSN_M(x, n, m) (x) & ((~(0U)<<(sizeof(x)-(m-n+1)))>>n)
  1. 取第n到m位的相反位
#define GET_REVERSE_BITS(x, n, m) (x) ^ ((~(0U)<<(sizeof(x)-(m-n+1)))>>n)

巧用位運算解算法題

  1. 老鼠試毒問題
    有8個如出一轍的瓶子,其中有7瓶是水,一瓶是毒藥。任何喝下毒藥的生物都會在一個星期以內死亡。如今你有三隻老鼠和一星期的時間,如何檢驗哪一個瓶子裏是毒藥?
    【解】
    1)把8個瓶子進行編號,0-7,使用二進制表示,以下:
000
   001
   010
   011
   100
   101
   110
   111

2)將第一位是1的瓶子裏的液體混合餵給第一隻老鼠吃,將第二位是1的瓶子裏的液體餵給第二隻老鼠吃,將第三位是1的瓶子裏的液體餵給第三隻老鼠吃。以後便可根據老鼠的死亡狀況肯定是那一瓶液體有毒。
如:第一、3只老鼠死亡。即第一位、第三位是1的瓶子裏必有毒,第二位是0,即爲101瓶子裏是毒藥。
【總結】:老鼠即爲所需的二進制位,假如現有1000瓶水,問你至少須要幾隻老鼠才能測出有毒的瓶子?2^10 = 1024 > 1000code

  1. Leetcode 232
    給定一個數,斷定他是否能夠用2的冪次方來表示,能夠返回true,不能夠返回false
    【常規解法】不斷用2去除,或者從1 乘到大於等於該數爲止。O(logn)
    【解】若是一個數是2的冪次方,則它一定能夠表示爲100....的形式,固然,0也能夠,因此該數的二進制表示至多有一個1。則能夠利用以前的將最後一個1設置爲0的技巧,循環遍歷至x爲0爲止。O(1)
int is2Power(int x)
{
    int y = abs(x);
    y &= (y-1); // 0也可使用
    if (!y)
    	return 1;
    else
    	return 0;
}
  1. Leetcode 232
    給定一個非負整數num, 對於0<=i<=num範圍中的每一個數字i,計算其二進制數中1的數目並將它們做爲數組返回。
    【常規解法】對每一個數字調用函數計算二進制數的數目。
    【解】利用x&(x-1)這個數比x的二進制位1的數目少1個
int bits[MAX] = {0};
int countBits(int num)
{
	int i;
	for (i = 1; i <= num; i++)
		bits[i] = bits[i&(i-1)]+1;
	
}
  1. 求解八皇后問題it

    八皇后問題,待補充解釋說明class

void queenSettle(row, colomn, Lline, Rline)
{
	int count = 0;
	//column二進制表示,1表明當前列以前行已經放置了棋子,不可再放棋子
	//Lline和Rline,表示以前行放置的棋子的左斜行和右斜行的位置,不可再放棋子
	int N = 8; // 8皇后問題
	if (row > = N)
	{
		//遍歷到最後一行,最後一行無需在找,只需找到空的那一列便可,說明已經找到了符合的解法
		count++;
		return ;
	}
	// 取出當前行可放置皇后的格子
	bits = ~((column|Lline|Rline)) & ((1 << N)-1); //按位與是隻取後N位,取反是爲了保證將原來0表示能夠放置棋子變成1能夠放置棋子
	while(bits > 0)
	{
		//每次從當前行可用的格子中取出最右邊位爲1的格子放置皇后
		p = bits & -bits;
		//緊接着在下一行繼續放皇后
		queenSettle(row+1, column|p, (Lline|p) << 1, (Rline|p) >> 1)
		//當前行最右邊的格子已經選完了,將其置爲0,表示已經這個格子已經遍歷過
		bits = bits & (bits-1);
	}	
}
相關文章
相關標籤/搜索