算法-只出現一次的數字
這三道題目也是Leetcode上的,考察的是對位運算的掌握程度。當然用HashMap也是可以做的。這裏只講位運算。
1、只出現一次的數字(I)
給定一個非空整數數組,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。
說明:
你的算法應該具有線性時間複雜度。 你可以不使用額外空間來實現嗎?
示例 1:
輸入: [2,2,1]
輸出: 1
示例 2:
輸入: [4,1,2,1,2]
輸出: 4
我們知道兩個相同的數字異或後結果爲0,任何數字和0異或等於它本身,所以我們將數組所有元素異或就得到解。
public int singleNumber(int[] nums) {
int n=0;
for(int i=0;i<nums.length;i++){
n^=nums[i];
}
return n;
}
2、只出現一次的數字(II)
給定一個非空整數數組,除了某個元素只出現一次以外,其餘每個元素均出現了三次。找出那個只出現了一次的元素。
說明:
你的算法應該具有線性時間複雜度。 你可以不使用額外空間來實現嗎?
示例 1:
輸入: [2,2,3,2]
輸出: 3
示例 2:
輸入: [0,1,0,1,0,1,99]
輸出: 99
我在這裏直接給出一個通用解法,在1個非空整數數組,除了某個元素出現1次以外,其他數字都出現k次。
我們對數組中每個數字的每一位進行檢查,如果統計對應位的1的數量不爲k的整數倍時,說明其是組成目標數字的位,反之不是,然後用按位或的操作就可以得到結果了
當k=3時,就是本題的答案,當k=2時,就是1的答案。
//nums:輸入數組 k:除某個元素外,剩餘元素都出現k次
public int singleNumber(int[] nums,int k) {
int result=0;
for(int i=0;i<32;i++){
int mask=1<<i;
int maskCount=0;
for(int n:nums){
if((n&mask)!=0){
maskCount++;
}
}
if(maskCount%k!=0){
result|=mask;
}
}
return result;
}
3、只出現1次的數字(III)
給定一個整數數組 nums,其中恰好有兩個元素只出現一次,其餘所有元素均出現兩次。 找出只出現一次的那兩個元素。
示例 :
輸入: [1,2,1,3,2,5]
輸出: [3,5]
注意:
結果輸出的順序並不重要,對於上面的例子, [5, 3] 也是正確答案。
你的算法應該具有線性時間複雜度。你能否僅使用常數空間複雜度來實現?
本題考察的仍然是位運算,延續1的思路,我們首先可以把所有數據異或,最後剩下的就是那兩個只出現一次的元素(記錄爲a、b)的異或值。
其中,這個值的非零位必然是屬於其中一個的,而不屬於另一個,這樣的話我們就將數據分成了兩部分,除a外的所有在此位和a相同的位元素組成的數組 同理b也是。
public int[] singleNumber(int[] nums) {
int result=0;
for(int i:nums){
result^=i;
}
int a=0,b=0;
for(int i=31;i>=0;i--){//找到第一個非0位
int mask=1<<i;
if((result&mask)!=0){//找到那一位
for(int n:nums){//遍歷數組,將數組分爲兩類
if((n&mask)!=0){
a^=n;
}else{
b^=n;
}
}
break;
}
}
return new int[]{a,b};
}