日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2025/4/16 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c语言或者cpp中位运算的技巧 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簡述

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

基礎

涉及到二進制運算,如下:

  • & | ^ 三種運算,分別對應著交,并,異或
    • 交:兩個對應位都是1,則為1,否則為0
    • 并:兩個對應位只有一個是1,則為1,否則為0
    • 異或:兩個對應位相同則為0,不同則為1
  • >> 往右移動,箭頭相反則為往左移動

這就是所有二進制的運算了。但就是由這里的這些推導出了很多有趣的運算范式。這些范式也可以稱之為基礎。

  • A為任何數,
    • 0 & A = 0
    • 0 | A = 0
    • 0 ^ A = A
    • A ^ A = 0

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

  • 明顯,三則運算滿足交換律和結合律。

這個驗證簡單,畫個表就知道了。只需要考慮任取一個位置,畫對應的表就好了。

  • 交換:A,B兩個數交換
    • A = A ^ B
    • B = A ^ B
    • A = A ^ B
    • 就完成交換了。

這種交換方式也是非常基礎的acm東西。如果解釋也是非常簡單的。(注意,下面的表達式中, 每個表達式的第一個均為賦值的意思,后面的等號就是相等的意思)

  • 第一步:A = A ^ B
  • 第二步實際上為:B = (A ^ B) ^ B,再由交換律和結合律,變為 B = A ^ (B ^ B) = A ^ 0 = 0 ^ A = A
  • 第三步實際上為:A = (A ^ B) ^ A, (原來這里的B已經是實際上的A了),同樣的, A = B。

擴展應用

數字去重

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

這里說的去重,是

  • 把重復兩次(或者是偶數次)的那些數字給去掉。
  • 而且數據集中只能有一個只出現一次的數字。

(應該是個相當naive的問題了)

這種問題,由于約束比default的版本更多,所以說,才可以用上這個答主給的那個版本的代碼。

例如:

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

方法: 異或

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"); }

去重改進

如上所說,可以改進到

  • 把重復兩次(或者是偶數次)的那些數字給去掉。
  • 而且數據集中只能有兩個只出現一次的數字。(且只能有兩個)

標準數據是:1 2 3 1 2 4

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

如下:

  • 注意到:這個時間復雜度是n2n^2n2的。(知乎上那個也是n2n^2n2),但他那個不好降低。
    • 優化,通過哈希的方式來降低時間復雜度。也可以使用平衡二叉樹。或者是平衡二叉樹和哈希的結合。
    • 平衡二叉樹的,插入,刪除,查找都是log(n)log(n)log(n)的。因此也不復雜度就被降到了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"); }

如果以后想到再繼續補充吧

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。