剑指offer56(Java)-数组中出现的次数Ⅰ(中等)
题目:
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
限制:
2 <= nums.length <= 10000
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
暴力求解:哈希表,但是不符合空间复杂度
先用哈希表统计出每个数字出现的次数,由于只有两个数字出现了一次,然后遍历哈希表,将出现一次的数字放入长度为2 的数组中返回即可。
1 class Solution { 2 public int[] singleNumbers(int[] nums) { 3 Map<Integer,Integer> map = new HashMap<>(); 4 int i = 0; 5 for(int num : nums){ 6 map.put(num, map.getOrDefault(num,0) + 1); 7 } 8 int[] ans = new int[2]; 9 for (Integer key: map.keySet()){ 10 if (map.get(key) == 1) { 11 ans[i] = key; 12 i++; 13 } 14 } 15 return ans; 16 } 17 }
异或:
异或公式:
① 交换律:A ^ B ^ C = A ^C ^ B
② A^ A = 0
③ A ^ 0 = A
故一个数组的元素进行异或:
比如:[2,4,2,3,3,6] 异或:2^4^2^3^3^6 = 4 ^ 6 ^(2^2)^(3^3) = 4 ^ 6 = 0100 ^ 0110 = 0010
思路:
①先将数组中的所有值进行异或,得到异或结果xor:
②设第一个为1的二进位为最后一位即0001,即设m = 1,让 m 不断左移来与xor做 与运算(相同为1)来找到第一位为1 的二进制位:
例如:
若x&0001=1,则a 的第一位为1,
若x&0010=1,则a 的第二位为1;
以此类推……
③根据num ^ m 是否等于0来差分数组。
具体过程可以看:K神老师以及评论区的解释
代码:
1 class Solution { 2 public int[] singleNumbers(int[] nums) { 3 int xor = 0; 4 //计算所有值的异或结果 5 for (int num : nums){ 6 xor ^= num; 7 } 8 int m = 1; 9 //找到第一位为1的二进制位,即当 m & xor = 1,保存m 10 while ((m & xor) == 0){ 11 //m左移1位 12 m <<= 1; 13 } 14 //利用m来将数组分组 15 //[4,1,4,6] xor = 1 ^ 6 = 0111,m = 0001 16 //num & m = 0的为一组:[4,4,6] 17 //num & m = 1的为一组:[1] 18 int x = 0, y = 0; 19 for (int num : nums){ 20 if ((num & m) == 0){ 21 x ^= num; 22 23 } 24 else{ 25 y ^= num; 26 } 27 } 28 return new int[]{x,y}; 29 } 30 }