c语言或者cpp中位运算的技巧
簡(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)
如果以后想到再繼續(xù)補(bǔ)充吧
總結(jié)
以上是生活随笔為你收集整理的c语言或者cpp中位运算的技巧的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: pandas内容像日期的数据如何变成真D
- 下一篇: 【解决办法】No module name