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