異或運算的應用

2021-10-06 04:35:11 字數 3376 閱讀 6249

異或的運用

unique-you 2018-03-22 13:31:36   1654   收藏 16

展開異或是一種基於二進位制的位運算,用符號xor或者 ^ 表示,其運算法則是對運算子兩側數的每乙個二進位制位,同值取0,異值取1。它與布林運算的區別在於,當運算子兩側均為1時,布林運算的結果為1,異或運算的結果為0。

異或的性質:

1、交換律:a^b = b^a;

2、結合律:(a^b)^c = a^(b^c);

3、對於任意的a:a^a=0,a^0=a,a^(-1)=~a。

了解了上面這些,來看看這個,很重要,後面的程式都要用到這個結論:

對於任意的a,有a^b^c^d^a^k = b^c^d^k^(a^a) = b^c^d^k^0 = b^c^d^k,也就是說,如果有多個數異或,其中有重複的數,則無論這些重複的數是否相鄰,都可以根據異或的性質將其這些重複的數消去,具體來說,如果重複出現了偶數次,則異或後會全部消去,如果重複出現了奇數次,則異或後會保留乙個。

下面來看三道題目:

1、1-1000放在含有1001個元素的陣列中,只有唯一的乙個元素值重複,其它均只出現一次。每個陣列元素只能訪問一次,設計乙個演算法,將它找出來;不用輔助儲存空間,能否設計乙個演算法實現?

當然,這道題,可以用最直觀的方法來做,將所有的數加起來,減去1+2+3+...+1000的和,得到的即是重複的那個數,該方法很容易理解,而且效率很高,也不需要輔助空間,唯一的不足時,如果範圍不是1000,而是更大的數字,可能會發生溢位。

我們考慮用異或操作來解決該問題。現在問題是要求重複的那個數字,我們姑且假設該數字式n吧,如果我們能想辦法把1-1000中除n以外的數字全部異或兩次,而數字n只異或一次,就可以把1-1000**n以外的所有數字消去,這樣就只剩下n了。我們首先把所有的數字異或,記為t,可以得到如下:

t = 1^2^3^4...^n...^n...^1000 = 1^2^3...^1000(結果中不含n)

而後我們再讓t與1-1000之間的所有數字(僅包含乙個n)異或,便可得到該重複數字n。如下所示:

t^(a^2^3^4...^n...^1000) = t^(t^n) = 0^n = n

2、乙個陣列中只有乙個數字出現了一次,其他的全部出現了兩次,求出這個數字。

明白了上面題目的推導過程,這個就很容易了,將陣列中所有的元素全部異或,最後出現兩次的元素會全部被消去,而最後會得到該只出現一次的數字。

該題目同樣可以該為如下情景,思路是一樣的:陣列中只有乙個數字出現了奇數次,其他的都出現了偶數次。

3、問題:乙個1~n的自然數的亂序陣列,其中缺失了1到n之間的某個數,如何快速找出這個數?

當n不太大時,可以考慮求和。先算出1~n的所有數的和,然後減去陣列**現的所有自然數的和。時間複雜度為o(n),空間複雜度o(1)。這種方法的缺點是n不能太大,n比較大時,求和容易溢位。

用位圖。從頭到尾的掃瞄整個陣列,把出現的數相應的位設定為1.然後再掃瞄位圖,找出不為1的那一位,即為要找的數。這種方法的時間複雜度為o(n),空間複雜度為o(n)。

可以把1~n的所有數異或,再把陣列**現的所有數異或,然後再把這兩個異或的結果異或,最後得到的值即為我們要找的值。這樣時間複雜度為o(n),空間複雜度為o(1)。在空間上比第二種方法要好,而且不會出現第一種方法中所說的溢位問題。

1.乙個整形陣列,存1到n的所有整數,但預設乙個值,找出此值。

先求1到n的異或,再和陣列中所有數異或,結果就是要找的值。

2.乙個整形陣列除乙個數隻出現一次外,其餘的都出現2次,求這個數

陣列中所有值進行異或即可。

3.乙個整形陣列除兩個數隻出現一次外,其餘的都出現2次,求這兩個數。

若求所有數的異或,得出的是那兩個數的異或值,這樣沒法分出兩數。

有兩種方法:(1)不同的兩個數進行異或,肯定有至少1位為1。比如,這兩個數的二進位制為1101和0001,異或結果為1100。那麼找出這個1,就可以把整個陣列分為兩部分,再利用2中的方法一一找出。

public static void findtwonumber(int a)    

int bit = 1; // 從最低位,即0001開始找

while (true)

else

}int re1 = 0;

int re2 = 0;

for (int i = 0; i < a.length; i++) else

}system.out.println(re1 + " " + re2);

}

(2)將所有數異或,得出的值為a^b,再一一和陣列中的值進行異或,得出的每個值存入乙個list,由於兩個數之外的值出現兩次,判斷陣列中若已存在此值,將其刪掉,最後list中就只有兩個值,即為a與b

public static void findtwonumber(int a) 

listlist = new arraylist();

for (int i = 0; i < a.length; i++) else

}system.out.println((list.get(0)) + " " + (list.get(1)));

}

5.乙個整形陣列除3個數只出現一次外,其餘的都出現2次,求這3個數。

將所有數異或,得出的值sum為a^b^c,再一一和陣列中的值進行異或,得出的每個值存入乙個list。將出現兩次的值刪掉,最後list中就只有三個值:a^b,a^c,b^c,三值與sum異或,即得c,b,a三個數。同理可求4個或更多出現一次的數。

public static void findthreenumber(int a) 

listlist = new arraylist();

for (int i = 0; i < a.length; i++) else

}system.out.println((sum ^ list.get(0)) + " " + (sum ^ list.get(1)) + " " + (sum ^ list.get(2)));

}

6.leetcode389.find the difference

string s 和 string t僅含小寫字母字元,其中t是s的重排且加了乙個字元,找到那個新加入的字元。題意示例:

input:

s = "abcd"

t = "abcde"

output:

e

對s和t的每個字元異或。

public static char findthedifference(string s, string t) 

for (int i = 0; i < t.length(); i++)

return a;

}

異或 運算的應用

1.異或運算 關於異或,有兩種計算。一是邏輯異或,一是按位異或。所謂邏輯異或就是運算數是true或者false。比如p1 true,p2 true,p1 p2。按位異或則是將變數轉化為二進位制,每一位分別異或。相同為0,不同為1。按位運算如 優先順序位於關係運算子之後,邏輯運算子之前。好像不經常強調...

異或運算的應用

異或是一種基於二進位制的位運算,用符號xor或者 表示,其運算法則是對運算子兩側數的每乙個二進位制位,同值取0,異值取1。它與布林運算的區別在於,當運算子兩側均為1時,布林運算的結果為1,異或運算的結果為0。交換律 a b b a 結合律 a b c a b c a b c d a b c 可以推出...

異或運算的應用

題目 1.將乙個數在二進位制狀態提取最右側的1後這個數為多少 2.提取乙個數轉為二進位制有多少個1 public class intgetrightnumber 怎麼把乙個int型別的數,提取出最右側的1後這個數為多少 static intgetnumber int flag 怎麼提取乙個數轉為二進...