136.Single Number---异或、位运算
题目大意:给出一串数组,里面的数都是两个,只有一个数是一个,把这个只有一个的数找出来。时间复杂度最好是线性的,空间复杂度最好为O(1).
法一:利用map,空间换时间,代码如下(耗时26ms):
1 public int singleNumber(int[] nums) { 2 Map<Integer, Integer> map = new HashMap<Integer, Integer>(); 3 int res = -1; 4 for(int i = 0; i < nums.length; i++) { 5 if(map.get(nums[i]) != null && map.get(nums[i]) == 1) { 6 map.put(nums[i], 2); 7 } 8 else { 9 map.put(nums[i], 1); 10 } 11 } 12 for(int i = 0; i < nums.length; i++) { 13 if(map.get(nums[i]) == 1) { 14 res = nums[i]; 15 break; 16 } 17 } 18 return res; 19 }
法二:先排序,再一个for循环,依次比较,代码如下(耗时8ms):
1 public int singleNumber(int[] nums) { 2 Arrays.sort(nums); 3 int res = nums[0]; 4 int cnt = 1; 5 boolean flag = false; 6 for(int i = 1; i < nums.length; i++) { 7 if(nums[i] != nums[i - 1]) { 8 if(cnt == 1) { 9 res = nums[i - 1]; 10 flag = true; 11 break; 12 } 13 cnt = 1; 14 } 15 else { 16 cnt++; 17 } 18 } 19 if(flag == false) { 20 res = nums[nums.length - 1]; 21 } 22 return res; 23 }
法三(借鉴):利用异或,由3^3=0知道,相同的两个数异或为0,不同的两个数异或为1。代码如下(耗时1ms):
1 public int singleNumber(int[] nums) { 2 int res = nums[0]; 3 for(int i = 1; i < nums.length; i++) { 4 res = res ^ nums[i]; 5 } 6 return res; 7 }
法四(借鉴):利用137题的法三,位运算,只是把对3取模改成对2取模即可。(num>>i)&1取num的第i位二进制数。ans |= sum <<i将二进制相加转为十进制。代码如下(耗时12ms):
1 public int singleNumber(int[] nums) { 2 int ans = 0; 3 int length = nums.length; 4 //将每一个数取二进制位按位相加,如果都是重复的则当前位的相加和一定是3的倍数,否则当前位一定存在于要找的那个数中 5 //比如1,1,1,2,2,2,3这六个数将其转为二进制数按位相加,然后每一位都对3取模,最后一定可以得到3 6 for(int i = 0; i < 32; i++) {//计算每一位 7 int sum = 0;//统计每一位的和 8 for(int j = 0; j < length; j++) {//对每个数取第i位的数值 9 if(((nums[j] >> i) & 1) == 1) {//取第i位的数值 10 sum++;//将每个数第i位的值相加求和 11 sum %= 2; 12 } 13 } 14 if(sum != 0) {//如果对3取模后非0,则说明当前位一定是要找的数的某一位 15 ans |= sum << i;//将其转为十进制加入结果当中 16 } 17 } 18 return ans; 19 }