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

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

生活随笔

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

c语言或者cpp中位运算的技巧

發(fā)布時(shí)間:2025/4/16 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c语言或者cpp中位运算的技巧 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

簡(jiǎn)述

在知乎上看到一個(gè)題目,解答很有意思,用的是位運(yùn)算。
這讓我覺(jué)得位運(yùn)算有更多的算法可能,但是卻還沒(méi)被我用過(guò)。
這種東西都是第一次看,覺(jué)得挺牛的,第二次,第三次看的時(shí)候就覺(jué)得沒(méi)什么了。So,大佬們輕噴。

基礎(chǔ)

涉及到二進(jìn)制運(yùn)算,如下:

  • & | ^ 三種運(yùn)算,分別對(duì)應(yīng)著交,并,異或
    • 交:兩個(gè)對(duì)應(yīng)位都是1,則為1,否則為0
    • 并:兩個(gè)對(duì)應(yīng)位只有一個(gè)是1,則為1,否則為0
    • 異或:兩個(gè)對(duì)應(yīng)位相同則為0,不同則為1
  • >> 往右移動(dòng),箭頭相反則為往左移動(dòng)

這就是所有二進(jìn)制的運(yùn)算了。但就是由這里的這些推導(dǎo)出了很多有趣的運(yùn)算范式。這些范式也可以稱(chēng)之為基礎(chǔ)。

  • A為任何數(shù),
    • 0 & A = 0
    • 0 | A = 0
    • 0 ^ A = A
    • A ^ A = 0

第三條需要解釋下:二進(jìn)制只有0或者1。0的二進(jìn)制任何位置都是0。A的數(shù),任何一個(gè)位置。如果是1,則1和0不同,該位置還是1。如果該位置為0,則0和0相同,該位置還是0。故不變

  • 明顯,三則運(yùn)算滿足交換律和結(jié)合律。

這個(gè)驗(yàn)證簡(jiǎn)單,畫(huà)個(gè)表就知道了。只需要考慮任取一個(gè)位置,畫(huà)對(duì)應(yīng)的表就好了。

  • 交換:A,B兩個(gè)數(shù)交換
    • A = A ^ B
    • B = A ^ B
    • A = A ^ B
    • 就完成交換了。

這種交換方式也是非常基礎(chǔ)的acm東西。如果解釋也是非常簡(jiǎn)單的。(注意,下面的表達(dá)式中, 每個(gè)表達(dá)式的第一個(gè)均為賦值的意思,后面的等號(hào)就是相等的意思)

  • 第一步:A = A ^ B
  • 第二步實(shí)際上為:B = (A ^ B) ^ B,再由交換律和結(jié)合律,變?yōu)?B = A ^ (B ^ B) = A ^ 0 = 0 ^ A = A
  • 第三步實(shí)際上為:A = (A ^ B) ^ A, (原來(lái)這里的B已經(jīng)是實(shí)際上的A了),同樣的, A = B。

擴(kuò)展應(yīng)用

數(shù)字去重

這個(gè)就是我之前說(shuō)的,看到了那篇文章:https://www.zhihu.com/question/33776070/answer/703697146?utm_source=wechat_session&utm_medium=social&utm_oi=806197504654839808

這里說(shuō)的去重,是

  • 把重復(fù)兩次(或者是偶數(shù)次)的那些數(shù)字給去掉。
  • 而且數(shù)據(jù)集中只能有一個(gè)只出現(xiàn)一次的數(shù)字。

(應(yīng)該是個(gè)相當(dāng)naive的問(wèn)題了)

這種問(wèn)題,由于約束比default的版本更多,所以說(shuō),才可以用上這個(gè)答主給的那個(gè)版本的代碼。

例如:

  • 數(shù)據(jù)集為 1 2 3 4 5 1 2 3 4, 那么我們要找到這個(gè)5
  • 其他實(shí)例為: 1 2 3 1 2 要找到 3。這里只會(huì)有一個(gè)目標(biāo)數(shù)字,且每個(gè)數(shù)字的重復(fù)都只有一次。
    • 1 2 1 2 1 2 3 這樣的數(shù)據(jù)就不行了。
    • 1 2 3 1 2 4 這樣的數(shù)據(jù)集,就需要改進(jìn)了。這個(gè)改進(jìn)回答也有,但我嫌棄他解釋的太麻煩。

方法: 異或

1^2^3^4^5^1^2^3^4 = (1^1)^(2^2)^(3^3)^(4^4)^5 = 0 ^ 5 = 5

#include <iostream> using namespace std;int main() {int a[] = { 1,2,3,4,5,1,2,3,4};int tmp = a[0];for (int i = 1; i < 9; ++i)tmp ^= a[i];cout << tmp << endl;system("pause"); }

去重改進(jìn)

如上所說(shuō),可以改進(jìn)到

  • 把重復(fù)兩次(或者是偶數(shù)次)的那些數(shù)字給去掉。
  • 而且數(shù)據(jù)集中只能有兩個(gè)只出現(xiàn)一次的數(shù)字。(且只能有兩個(gè))

標(biāo)準(zhǔn)數(shù)據(jù)是:1 2 3 1 2 4

  • 回憶下上一個(gè):
    • 其實(shí)我們這得到的就是第一步得到的 A ^ B
    • 那想把A或者B提取出來(lái)。按照知乎那哥們那么說(shuō)也是可以的。但是真的是麻煩
    • 簡(jiǎn)單點(diǎn): A ^ (A ^ B) = B。且異或運(yùn)算也是唯一性的。給一個(gè)數(shù)組,設(shè)置為空。
      • 遍歷:拿到第i個(gè)數(shù),是否已經(jīng)在上面新建的數(shù)組中了,在則這個(gè)數(shù)就是我們想要的,否者,將 這個(gè)數(shù)和A^B做異或的數(shù)值存下來(lái)。

如下:

  • 注意到:這個(gè)時(shí)間復(fù)雜度是n2n^2n2的。(知乎上那個(gè)也是n2n^2n2),但他那個(gè)不好降低。
    • 優(yōu)化,通過(guò)哈希的方式來(lái)降低時(shí)間復(fù)雜度。也可以使用平衡二叉樹(shù)。或者是平衡二叉樹(shù)和哈希的結(jié)合。
    • 平衡二叉樹(shù)的,插入,刪除,查找都是log(n)log(n)log(n)的。因此也不復(fù)雜度就被降到了O(nlogn)
#include <iostream> using namespace std;int main() {int a[] = { 1,2,3,1,2,4 };int b[] = { 0,0,0,0,0,0 };int tmp = a[0], i, j;for (i = 1; i < 7; ++i)tmp ^= a[i];for (i = 0; i < 7; ++i) {for (j = 0; j < i; ++j) { if (b[j] == a[i]) { cout << a[i] << " " << (tmp ^ a[i]) << endl; break; } }if (j != i) break;b[i] = tmp ^ a[i];}system("pause"); }

如果以后想到再繼續(xù)補(bǔ)充吧

總結(jié)

以上是生活随笔為你收集整理的c语言或者cpp中位运算的技巧的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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