leetcode 剑指 Offer 56 - II. 数组中数字出现的次数 II

在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。

示例 1:

输入:nums = [3,4,3,3]
输出:4

示例 2:

输入:nums = [9,1,7,9,7,9,7]
输出:1

限制:

1 <= nums.length <= 10000
1 <= nums[i] < 2^31

解法一:

使用HashMap统计每个元素出现的次数,最后再遍历一次map即可

 1 class Solution {
 2     public int singleNumber(int[] nums) {
 3         
 4         // 使用HashMap的方式,使用map统计每个元素出现的次数
 5         HashMap<Integer, Integer> map = new HashMap<>();
 6         int len = nums.length;
 7         for(int i = 0; i < len; ++i){
 8             if(map.containsKey(nums[i])){
 9                 map.put(nums[i], map.get(nums[i]) + 1);
10             }else{
11                 map.put(nums[i], 1);
12             }
13         }
14         // 遍历一遍map, 找到次数为1的数字
15         for(Map.Entry<Integer, Integer> en: map.entrySet()){
16             if(en.getValue() == 1){
17                 return en.getKey();
18             }
19         }
20         return 0;
21     }
22 }

leetcode运行时间:17ms, 空间:39.9MB

复杂度分析:

空间复杂度:Map中的键值对个数, O(n/3)

时间复杂度:一次遍历数组,一次遍历map, 所以时间复杂度为O(n)

解法二:

 使用位运算,一个长度为32的int数组,记录了所有元素二进制在第i位的值之和,最后将数组第i位的值对3取余后将数组转换成二进制数,这个二进制数表示的数字即为该整数

 1 class Solution {
 2     public int singleNumber(int[] nums) {
 3         
 4         int[] arr = new int[32];
 5         int len = nums.length;
 6         for(int i = 0; i < len; i++){
 7             for(int j = 0; j < 32; j++){
 8                 arr[j] += (nums[i] & 1);      // 记录每个元素各个位的值
 9                 nums[i] >>= 1;
10             }
11         }
12 
13         int temp = 0;
14         for(int i = 31; i >= 0; i--){
15             temp <<= 1;
16             temp |= (arr[i] % 3);         // 将temp的最后一位设置成arr[i] % 3
17         }
18         return temp;
19     }
20 }

leetcode运行时间为:8ms, 空间为39.8mb

复杂度分析:

时间复杂度:时间复杂度主要是前阶段的双重 for 循环,所以时间复杂度为O(32n)

空间复杂度:一个长度为32的 int 数组, 所以空间其实可以说是O(1), 因为空间大小是固定的,不随着nums数组的元素增多而变化。