日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

位运算——强大得令人害怕

發(fā)布時(shí)間:2023/12/14 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 位运算——强大得令人害怕 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

眾所周知,位運(yùn)算是我們學(xué)計(jì)算機(jī)必學(xué)的東西,前人用二進(jìn)制、位運(yùn)算給我們了一個(gè)操作簡(jiǎn)單的計(jì)算機(jī),但我們卻很少接觸位運(yùn)算了。今天介紹一些位運(yùn)算在算法中的運(yùn)用。

位運(yùn)算基礎(chǔ)

  • &
    • 按位與
    • 如果兩個(gè)相應(yīng)的二進(jìn)制位都為1,則該位的結(jié)果值為1,否則為0
  • |
    • 按位或
    • 兩個(gè)相應(yīng)的二進(jìn)制位中只要有一個(gè)為1,該位的結(jié)果值為1
  • ^
    • 按位異或
    • 若參加運(yùn)算的兩個(gè)二進(jìn)制位值相同則為0,否則為1
  • ~
    • 取反
    • ~是一元運(yùn)算符,用來(lái)對(duì)一個(gè)二進(jìn)制數(shù)按位取反,即將0變1,將1
  • <<
    • 左移
    • 用來(lái)將一個(gè)數(shù)的各二進(jìn)制位全部左移N位,右補(bǔ)0
  • >>
    • 右移
    • 將一個(gè)數(shù)的各二進(jìn)制位右移N位,移到右端的低位被舍棄,對(duì)于無(wú)符號(hào)數(shù), 高位補(bǔ)0

奇技淫巧

1.技巧一:用于消去x的最后一位的1

x & (x-1) x = 1100 x-1 = 1011 x & (x-1) = 1000

1.1.應(yīng)用一 用O(1)時(shí)間檢測(cè)整數(shù)n是否是2的冪次.

  • 思路解析:N如果是2的冪次,則N滿(mǎn)足兩個(gè)條件。
    1.N>0
    2.N的二進(jìn)制表示中只有一個(gè)1
    一位N的二進(jìn)制表示中只有一個(gè)1,所以使用N&(N-1)將唯一的一個(gè)1消去。
    如果N是2的冪次,那么N&(N-1)得到結(jié)果為0,即可判斷。

1.2.應(yīng)用二 計(jì)算在一個(gè) 32 位的整數(shù)的二進(jìn)制表示中有多少個(gè) 1.

  • 思路解析:
    由 x & (x-1) 消去x最后一位知。循環(huán)使用x & (x-1)消去最后一位1,計(jì)算總共消去了多少次即可。

1.3.將整數(shù)A轉(zhuǎn)換為B,需要改變多少個(gè)bit位

  • 思路解析
    這個(gè)應(yīng)用是上面一個(gè)應(yīng)用的拓展。
    思考將整數(shù)A轉(zhuǎn)換為B,如果A和B在第i(0<=i<32)個(gè)位上相等,則不需要改變這個(gè)BIT位,如果在第i位上不相等,則需要改變這個(gè)BIT位。所以問(wèn)題轉(zhuǎn)化為了A和B有多少個(gè)BIT位不相同。聯(lián)想到位運(yùn)算有一個(gè)異或操作,相同為0,相異為1,所以問(wèn)題轉(zhuǎn)變成了計(jì)算A異或B之后這個(gè)數(shù)中1的個(gè)數(shù)。

2.技巧二 使用二進(jìn)制進(jìn)行子集枚舉

應(yīng)用.給定一個(gè)含不同整數(shù)的集合,返回其所有的子集

樣例

如果 S = [1,2,3],有如下的解:
[ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2] ]

思路

思路就是使用一個(gè)正整數(shù)二進(jìn)制表示的第i位是1還是0,代表集合的第i個(gè)數(shù)取或者不取。所以從0到2n-1總共2n個(gè)整數(shù),正好對(duì)應(yīng)集合的2^n個(gè)子集。

S = {1,2,3} N bit Combination 0 000 {} 1 001 {1} 2 010 {2} 3 011 {1,2} 4 100 {3} 5 101 {1,3} 6 110 {2,3} 7 111 {1,2,3}

解題代碼

之后補(bǔ)充。

技巧三.a^b^b=a

3.1.應(yīng)用一 數(shù)組中,只有一個(gè)數(shù)出現(xiàn)一次,剩下都出現(xiàn)三次,找出出現(xiàn)一次的。

問(wèn)題

Given [1,2,2,1,3,4,3], return 4

解題思路

因?yàn)橹挥幸粋€(gè)數(shù)恰好出現(xiàn)一個(gè),剩下的都出現(xiàn)過(guò)兩次,所以只要將所有的數(shù)異或起來(lái),就可以得到唯一的那個(gè)數(shù)。

C語(yǔ)言解題代碼
#include<stdio.h> int main() {int a[7]={1,2,2,1,3,4,3};int ans=0;for(int i=0;i<7;i++){ans^=a[i];}printf("%d\n",ans); }

3.2.應(yīng)用二 數(shù)組中,只有一個(gè)數(shù)出現(xiàn)一次,剩下都出現(xiàn)三次,找出出現(xiàn)一次的。

問(wèn)題

Given [1,1,2,3,3,3,2,2,4,1] return 4

解題思路

因?yàn)閿?shù)是出現(xiàn)三次的,也就是說(shuō),對(duì)于每一個(gè)二進(jìn)制位,如果只出現(xiàn)一次的數(shù)在該二進(jìn)制位為1,那么這個(gè)二進(jìn)制位在全部數(shù)字中出現(xiàn)次數(shù)無(wú)法被3整除。
模3運(yùn)算只有三種狀態(tài):00,01,10,因此我們可以使用兩個(gè)位來(lái)表示當(dāng)前位%3,對(duì)于每一位,我們讓Two,One表示當(dāng)前位的狀態(tài),B表示輸入數(shù)字的對(duì)應(yīng)位,Two+和One+表示輸出狀態(tài)。

0 0 0 0 00 0 1 0 10 1 0 0 10 1 1 1 01 0 0 1 01 0 1 0 0One+ = (One ^ B) & (~Two)Two+ = (~One+) & (Two ^ B)
C語(yǔ)言解題代碼
#include<stdio.h>void findNum(int *a,int n) {int one=0;int two=0;int i,j,k;for(i=0;i<n;i++){two=two|(one&a[i]);one=one^a[i];int three=two&one;two=two^three;one=one^three;}printf("%d\n",one|two); } int main() {int a[10]={1,1,2,3,3,3,2,2,4,1};findNum(a,10); }

另外一種容易理解的方法

#include<stdio.h>void findNum(int *a,int n) {int ans=0;int bits[32]={0};for(int i=0;i<n;i++){for(int j=0;j<32;j++){bits[j]+=((a[i]>>j)&1);}}for(int i=0;i<32;i++){if(bits[i]%3==1) ans+=1<<i;}printf("%d\n",ans); } int main() {int a[10]={1,1,2,3,3,3,2,2,4,1};findNum(a,10); }

3.3.應(yīng)用三 數(shù)組中,只有兩個(gè)數(shù)出現(xiàn)一次,剩下都出現(xiàn)兩次,找出出現(xiàn)一次的

問(wèn)題

Given [1,2,2,3,4,4,5,3] return 1 and 5

解題思路

有了第一題的基本的思路,我們不妨假設(shè)出現(xiàn)一個(gè)的兩個(gè)元素是x,y,那么最終所有的元素異或的結(jié)果就是res = x^y。并且res!=0,那么我們可以找出res二進(jìn)制表示中的某一位是1,那么這一位1對(duì)于這兩個(gè)數(shù)x,y只有一個(gè)數(shù)的該位置是1。對(duì)于原來(lái)的數(shù)組,我們可以根據(jù)這個(gè)位置是不是1就可以將數(shù)組分成兩個(gè)部分。求出x,y其中一個(gè),我們就能求出兩個(gè)了。

C語(yǔ)言解題代碼
#include<stdio.h>void findNum(int *a,int n) {int ans=0;int pos=0;int x=0,y=0;for(int i=0;i<n;i++)ans^=a[i];int tmp=ans;while((tmp&1)==0){//終止條件是二進(jìn)制tmp最低位是1pos++;tmp>>=1;}for(int i=0;i<n;i++){if((a[i]>>pos)&1){//取出第pos位的值x^=a[i];}}y=x^ans;if(x>y) swap(x,y);//從大到小輸出x,yprintf("%d %d\n",x,y); } int main() {int a[8]={1,2,2,3,4,4,5,3};findNum(a,8); }

另外一種寫(xiě)法

#include<stdio.h>void findNum(int *a,int n) {int diff=0;int x=0,y=0;for(int i=0;i<n;i++){diff^=a[i];}diff&=-diff;//取diff的最后一位1的位置for(int i=0;i<n;i++){if((a[i]&diff)==0){x^=a[i];}else y^=a[i];}if(x>y) swap(x,y);printf("%d %d\n",x,y); } int main() {int a[10]={1,2,2,3,4,4,5,3};findNum(a,8); }

參考自大神:
微信:ninechapter。

總結(jié)

以上是生活随笔為你收集整理的位运算——强大得令人害怕的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。