写这篇博客主要是为了说明在部分场景中位运算的便利。
题目只出现一次的数字1描述
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
不使用额外空间:即空间复杂度为O(1)。
示例 1:
输入: [2,2,1] 输出: 1
示例 2:
输入: [4,1,2,1,2] 输出: 4
算法思路
对于这道题,可使用异或运算。异或运算有以下三个性质。
- 任何数和 0 做异或运算,结果仍然是原来的数。
- 任何数和其自身做异或运算,结果是 0。
- 异或运算满足交换律和结合律。
代码
class Solution:
def singleNumber(self, nums: List[int]) -> int:
n = len(nums)
res = 0
for i in range(n):
res ^= nums[i]
return res
题目只出现一次的数字2描述
给你一个整数数组 nums
,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。
示例 1:
输入:nums = [2,2,3,2] 输出:3
示例 2:
输入:nums = [0,1,0,1,0,1,99] 输出:99
算法思路
考虑答案的第 i 个二进制位(i从 0 开始编号),它可能为 0 或 1。对于数组中非答案的元素,每一个元素都出现了 3 次,对应着第 i 个二进制位的 3 个 0 或 3 个 1,无论是哪一种情况,它们的和都是 3 的倍数(即和为 0 或 3)。因此:对于数组中的每一个元素 x,我们使用位运算 (x >> i) & 1 得到 x 的第 i个二进制位,并将它们相加再对 3 取余,得到的结果一定为 0 或 1,即为答案的第 i 个二进制位。
需要注意的是,如果使用的语言对「有符号整数类型」和「无符号整数类型」没有区分,那么可能会得到错误的答案。这是因为「有符号整数类型」(即int类型)的第31个二进制位(即最高位)是补码意义下的符号位,对应着-231,而「无符号整数类型」由于没有符号,第31个二进制位对应着23。因此在某些语言(例如Python)中需要对最高位进行特殊判断。
代码
class Solution:
def singleNumber(self, nums: List[int]) -> int:
ans = 0
for i in range(32):
total = sum((num>>i)&1 for num in nums)
if total % 3:
if i == 31:
ans -= 1<<i
else:
ans |= 1<<i
return ans