题目1:数组中只出现一次的两个数字
一个整型数组中除了两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。
要求时间复杂度O(n),空间复杂度O(1)。
例:
输入:[2, 4, 3, 6, 3, 2, 5, 5]
输出:4, 6
思路
- 利用异或运算的特点,a^a = 0;0^a = a。第一次遍历异或的结果为s = n1 ^ n2。此时s的二级制位表征了n1和n2各位上的异同。只要将n1和n2分在两个子数组中,并再次异或遍历,即可得到各自的值。因此用s中为1的位来划分子数组即可。
- 时间复杂度:O(n)
- 空间复杂度:O(1)
代码
思路1:时间复杂度:O(n),空间复杂度:O(1)
def numbers_appear_once(nums):
"""
:param nums:array
:return: (num1, num2)
"""
if not nums:
return None
s = n1 = n2 = 0
for num in nums:
s ^= num
bit = 0
while s & 1 == 0:
s = s >> 1
bit += 1
div = 1 << bit
for num in nums:
if num & div:
n1 ^= num
else:
n2 ^= num
return n1, n2
题目2:数组中唯一只出现一次的数字
在一个数组中除一个数字只出现一次之外,其他数字都出现了三次。
思路
- 遍历数组不进位相加后得到,
s
=
n
0
+
n
1
+
.
.
.
+
n
i
=
<
b
0
,
b
1
,
b
2
,
.
.
.
,
b
i
>
s =n_0+n_1+...+n_i = <b_0, b_1, b_2,..., b_i>
s=n0+n1+...+ni=<b0,b1,b2,...,bi>,
b
i
=
3
∗
(
n
0
+
.
.
.
+
n
n
u
m
−
1
+
n
n
u
m
+
1
+
.
.
+
n
i
)
+
n
n
u
m
b_i=3*(n_0+...+n_{num-1}+n_{num+1}+..+n_i) +n_{num}
bi=3∗(n0+...+nnum−1+nnum+1+..+ni)+nnum,只要将每二进制位上的和对3求余即可。
- 时间复杂度:O(n)
- 空间复杂度:O(1)
- 本题仍然能够用异或来解。要求是构造一个运算@,运算三次归零。0@S@S@S=0。 b = ~a & (b ^ num);a = ~b & (a ^ num)。分析运算的过程,该运算本质是用【ab】=00->01->10->00表示出现的次数。当该数字只有一次时,b相当于完成一次异或,b=num,a=0;运算第二次,b=num^num = 0,a = num;运算第三次,b=0,a=0。用2个比特位来记录。
- 时间复杂度:O(n) 快于思路1。
- 空间复杂度:O(1)
代码
思路1:时间复杂度:O(n),空间复杂度:O(1)
def number_appearing_once(nums):
cache = [0] * 32
for num in nums:
bit_mask = 1
for i in range(31,-1,-1):
if num & bit_mask:
cache[i] += 1
bit_mask = bit_mask << 1
ans = 0
for i in range(32):
ans = ans << 1
ans += cache[i] % 3
return ans if ans < 2 ** 31 else ans - 2 ** 32
思路2:时间复杂度:O(n),空间复杂度:O(1)
def number_appearing_once_2(nums):
a, b = 0, 0
for num in nums:
b = ~a & (b ^ num)
a = ~b & (a ^ num)
return b
思考
相同的题目
LeetCode 137. 只出现一次的数字 II
题目
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,3,2]
输出: 3
示例 2:
输入: [0,1,0,1,0,1,99]
输出: 99