力扣第137题-只出现一次的数字 II

158 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

前言

力扣第137题 只出现一次的数字 II 如下所示:

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。 请你找出并返回那个只出现了一次的元素。

示例 1:

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

示例 2:

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

提示:

  • 1 <= nums.length <= 3 * 104
  • -231 <= nums[i] <= 231 - 1
  • nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次

进阶: 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

一、思路

这一题与前面的力扣第136题-只出现一次的数字很类似,都是找出仅出现一次的元素。先整理一下题目中的重要信息: 某个元素仅会出现 1 次,而其它元素都会出现 3 次。

我们前面一题利用的是位运算中的 异或运算 来快速寻找(遍历一次且不需要额外空间)到出现过一次的的元素。但是很显然这一题不能用这个思路来实现了,因为 a⊕a⊕a = 0⊕a = a

如果不考虑时间和空间复杂度的话,昨天思路中提到的 哈希表 也可以用于解这一题。大致的思路为先统计各字符出现的次数,然后再找出出现一次的元素即可。

image.png

但是这样你会发现元素出现 3 次其实是没有利用到的,我后来看题解发现官方提到的 二进制位 还是蛮有趣的。

二进制位

以下的思路总结来自于官方题解,如有错误的地方,欢迎指正!

以示例一中的 nums = [2,2,3,2] 作为例子,它们的二进制如下所示:

image.png

我们统计每一位上的 1 的数量和后对 3 取余,如下所示:

image.png

通过统计每一位上 1 的数量,就可以找到只出现过一次的数量。

综上所述,该题大致的步骤如下所示:

  1. 从低位到高位统计数组中 1 出现的次数
  2. 再将结果对 3 取余,取余剩下的值合在一起就是只出现过一次的元素

二、实现

实现代码

实现代码与思路中保持一致

public int singleNumber(int[] nums) {
    int ret = 0;
    // 从低位到高位
    for (int i=0; i < 32; i++) {
        int count = 0;  // 计数
        for (int n: nums) {
            count  += ((n >> i) & 1);
        }
        if (count%3 != 0) {
            // 进行或操作
            ret |= (1 << i);
        }
    }
    return ret;
}

测试代码

public static void main(String[] args) {
    int[] nums = {2, 3, 3, 3};
    new Number137().singleNumber(nums);
}

结果

image.png

三、总结

感谢看到最后,非常荣幸能够帮助到你~♥

如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~