只出現一次的數字系列
- 異或的性質
- 兩個數字異或的結果a^b是將 a 和 b 的二進制每一位進行運算,得出的數字。 運算的邏輯是
- 如果同一位的數字相同則爲 0,不同則爲 1
- 異或的規律
-
任何數和本身異或則爲 0
-
任何數和 0 異或是 本身
-
異或滿足交換律。 即 a ^ b ^ c ,等價於 a ^ c ^ b
136. 只出現一次的數字 1
給定一個非空整數數組,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。
class Solution {
public int singleNumber(int[] nums) {
int sum = 0;
for(int i =0; i < nums.length; i++){
sum ^= nums[i];
}
return sum;
}
}
面試題56 - I. 數組中數字出現的次數
題目描述
一個整型數組裏除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字
###方法1 hashmap
- 時間O(N)
- 空間O(N)
//num1,num2分別爲長度爲1的數組。傳出參數
//將num1[0],num2[0]設置爲返回結
import java.util.HashMap;
public class Solution {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int i = 0; i < array.length; i++){
if(map.containsKey(array[i])) map.put(array[i], 2);
else map.put(array[i], 1);
}
int count = 0; //記錄num1是否被填充
for(int i = 0; i < array.length; i++){
if(map.get(array[i]) == 1){
if(count == 0){
num1[0] = array[i];
count++;
}else{
num2[0] = array[i];
}
}
}
}
}
方法2 位運算
- 時間O(N)
- 空間O(1)
//num1,num2分別爲長度爲1的數組。傳出參數
//將num1[0],num2[0]設置爲返回結果
import java.util.HashMap;
public class Solution {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
int sum =0; // 保存兩兩以獲得結果,其結果等於兩個只出現一次的元素的異或值。
//將數組所有元素進行異或,最後的結果一定是那兩個單一數字的異或結果。看上圖示例
//用示例[4,4,6,1]最後異或結果就是 6和1異或的結果 7
for(int i = 0; i < array.length; i++){
sum ^= array[i];
}
// 記錄第一次接獲結果其從低位到高位第一個爲1的首位。
// 爲什麼要找它? 以爲兩個不一樣的值 其位運算第一次發生不一樣的時候,該位位運算結果就是1,找到該位置
// 可以把整個數組劃分爲兩個部分。
int first = 1;
while((sum & first) == 0){ // 爲0進位,爲1不執行循環。
first = first << 1;
}
//first爲1,所以我們可以根據數組元素的二進制低位第一位是否爲1,將數組分爲2類,
// 示例數組可以分爲 低位第一位爲0:[4,4,6] 低位第一位爲1:[1]
//此時再將兩個數組兩兩異或就可以得到最終結果。
for(int i = 0; i < array.length; i++){
// 將數組分類
if((array[i] & first) == 0){
num1[0] ^= array[i];
}else{
num2[0] ^= array[i];
}
}
}
}
137. 只出現一次的數字 II
給定一個非空整數數組,除了某個元素只出現一次以外,其餘每個元素均出現了三次。找出那個只出現了一次的元素
class Solution {
public int singleNumber(int[] nums) {
int res = 0;
// int型數據,最多隻有32位。
for(int i = 0; i < 32; i++){
int count = 0;
int bit = 1 << i;
for(int j = 0; j < nums.length; j++){
// 如果三個相同的數在該位爲0,count不加
// 如果三個相同的數在該位不爲0,count加,那麼,如果單獨的數與該位與後爲0,最後count一定是3的倍數。否則需要作與運算還原該位。
if((bit & nums[j]) != 0){
count++;
}
}
if((count % 3) != 0){
res |= bit;
}
}
return res;
}
}
- 牛客網,需要自定義輸入。類名統一用Main!
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int [] nums = new int[n];
for(int i = 0; i < n; i++){
nums[i] = in.nextInt();
}
System.out.print(find(nums));
in.close();
}
public static int find(int [] nums){
int res = 0;
// int型數據,最多隻有32位
for(int i = 0; i < 32; i++){
int count = 0;
int bit = 1 << i;
for(int j = 0; j < nums.length; j++){
// 如果三個相同的數在該位爲0,count不加
// 如果三個相同的數在該位不爲0,count加,那麼,如果單獨的數與該位與後爲0,最後count一定是3的倍數。否則需要作與運算還原該位。
if((bit & nums[j]) != 0){
count++;
}
}
if((count % 3) != 0){
res |= bit;
}
}
return res;
}
}