【LeetCode】只出现一次的数字 IIIJava题解

210 阅读3分钟

这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战

题目描述

给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。

 

进阶:你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?

 

示例 1:

输入:nums = [1,2,1,3,2,5]
输出:[3,5]
解释:[5, 3] 也是有效的答案。
示例 2:

输入:nums = [-1,0]
输出:[-1,0]
示例 3:

输入:nums = [0,1]
输出:[1,0]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/single-number-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路分析

  • 今天的算法题目是数组题目,题目要求其中恰好有两个元素只出现一次,其余所有元素均出现两次。,注意这个条件,只有两个元素只出现一次。
  • 我们首先采用朴素解法,使用 hashMap 将所有的元素都遍历一遍并计数。然后在遍历一次 hashMap 取出出现次数是一次的元素,即为答案。
  • 进阶解法要求的需要使用常量的空间复杂度实现,可以采用位运算解法。异或运算(xor)两个位相同为0,相异为1。
  • 异或运算(xor)常见规律如下:
  1. 归零律(任何数和其自身做异或运算,结果是 0):a xor a = 0
  2. 恒等律(任何数和 0 做异或运算,结果仍然是原来的数):a xor 0 = a
  3. 交换律:a xor b = b xor a
  4. 结合律:a xor b xor c = a xor (b xor c ) = (a xor b) xor c
  • 利用异或运算的性质。我们首先对 nums 中的所有元素执行异或操作,得到两个只出现一次的元素的异或值。
  • 然后取 sum 二进制表示中为 1 的任意一位 k,sum 中的第 k 位为 1 意味着两答案的第 k 位二进制表示不同。
  • 因为已知sum的第k位为1,说明这两个数的第k位一个为0,一个为1,因此可以将nums中的元素分成两组,一组里边的元素的第k位都为0,另一组都为1,对每一组的元素分别求异或,因为其他的元素都有两个,异或的结果都为0,所以每一组的异或结果即为答案之一。实现代码如下:

通过代码

  • 朴素算法
class Solution {
    public int[] singleNumber(int[] nums) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int num : nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }
        int[] ans = new int[2];
        int j = 0;
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            if (entry.getValue() == 1) {
                ans[j++] = entry.getKey();
            }
        }

        return ans;
    }
}
  • 位运算解法
class Solution {
    public int[] singleNumber(int[] nums) {
        int sum = 0;
        for (int num : nums) {
            sum ^= num;
        }
        int k = -1;
        for (int i = 31; i >= 0 && k == -1; i--) {
            if (((sum >> i) & i) == 1) {
                k = i;
                break;
            }
        }

        int[] ans = new int[2];
        for (int num : nums) {
            if (((num >> k) & 1 )== 1) {
                ans[1] ^= num; 
            } else {
                ans[0] ^= num; 
            }
        }

        return ans;
    }
}

image.png

总结

  • 朴素解法的时间复杂度是O(n),空间复杂度是O(n)
  • 位运算解法的时间复杂度是O(n), 空间复杂度是O(1)
  • 坚持算法每日一题,加油!