Leetcode 剑指 Offer II 004. 只出现一次的数字
创始人
2024-03-14 18:06:38
0次

题目难度: 中等

原题链接

今天继续更新 Leetcode 的剑指 Offer(专项突击版)系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~

题目描述

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

示例 1:

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

示例 2:

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

提示:

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

进阶

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

题目思考

  1. 如何利用恰好出现 3 次这一条件?
  2. 如何既做到线性时间复杂度, 又不使用额外空间?

解决方案

思路

  • 分析题目, 一个很容易想到的方法使用一个计数字典存储每个数字的出现次数, 最后找到出现次数为 1 的数字即可
  • 这种算法虽然做到了线性时间复杂度, 但需要额外的空间 (计数字典), 如何满足题目的进阶要求呢?
  • 我们换一个角度, 考虑二进制『每一位』的计数
  • 注意到其他数字都出现 3 次, 那么如果我们累加这一位上 1 的计数, 那么出现 3 次的数字对该计数的贡献值一定也是 3 的倍数
  • 所以最终一定只有两种情况:
    • a. 计数模 3 的余数为 0 => 出现 1 次的数字在该位上也是 0
    • b. 计数模 3 的余数为 1 => 出现 1 次的数字在该位上也是 1
  • 有了这个结论, 我们就可以依次遍历二进制的每一位, 然后应用上述判断, 从而组装出那个出现 1 次的数字
  • 另外特别注意, 由于 python 的语言特性, 它的第 32 位并不是符号位, 当它为 1 时并不像其他语言的 32 位数字一样表示负数
  • 所以我们需要将其更高位都填充为 1 才行, 具体做法就是先获得 32 位下取反后对应的正数 (与 0xFFFFFFFF 异或), 再整体取反即可
  • 下面代码中对上述每个步骤都有详细注释, 方便大家理解

复杂度

  • 时间复杂度 O(N): 外层循环需要遍历每一位 O(32), 内层循环需要遍历每个数字 O(N), 整体就是 O(32N), 等价于 O(N)
  • 空间复杂度 O(1): 只使用了几个常数空间的变量

代码

class Solution:def singleNumber(self, nums: List[int]) -> int:res = 0for i in range(32):cnt = 0for x in nums:# 统计所有数字在这一位上1的计数cnt += (x >> i) & 1if cnt % 3 == 1:# 说明只出现一次的数字对这一位贡献了1# 因为其他数字都出现3次, 它们在这一位的计数和对3取模肯定是0res += 1 << iif i == 31:# 第31位是1, 说明是负数, 需要将更高位也转成1, 转成正确的负数表示形式res = ~(0xFFFFFFFF ^ res)return res

大家可以在下面这些地方找到我~😊

我的 GitHub

我的 Leetcode

我的 CSDN

我的知乎专栏

我的头条号

我的牛客网博客

我的公众号: 算法精选, 欢迎大家关注~😊

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...