剑指 Offer 56 - I 至 56 - II 数组中数字出现的次数 I && II 题解
Posted 风去幽墨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指 Offer 56 - I 至 56 - II 数组中数字出现的次数 I && II 题解相关的知识,希望对你有一定的参考价值。
剑指 Offer 56 - I. 数组中数字出现的次数
题意:
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
题解:
面试常考题。
最原始版本(最简单版本):
一个整型数组 nums 里除一个数字之外,其他数字都出现了偶数次。
请写程序找出这两个只出现一次的数字。
要求时间复杂度是O(n),空间复杂度是O(1)。
根据异或的原理 a^b^a = b,a^a = 0。很容易得到整体异或后最终结果即为答案。
升级版本 1.0 就是这道题。
区别于简单版本是有两个数字(记为a,b)出现了偶数次。
这里依然可以顺着异或的方向去思考,整体异或的结果是a^b。很明显a和b是不同的,所以a^b的结果必然不是0,那么肯定在二进制下有某一位为1,只有0^1=1^0 =1,所以可以得到a和b在这一位上有一个为0一个为1。依据这个可以将所有元素分为两组,一组在该位上为1,一组为0.然后将两组元素各自异或后得到的结果就是a和b。
代码:
class Solution:
def singleNumbers(self, nums: List[int]) -> List[int]:
sum = nums[0]
for i in nums[1:]:
sum^=i
for i in range(0,32):
if sum&(1<<i):
a,b=None,None
for j in nums:
if j&(1<<i):
a = a^j if a else j
else:
b = b^j if b else j
break
return [a,b]
剑指 Offer 56 - II. 数组中数字出现的次数 II
题意:
在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
题解:
解法1:位运算(暴力解法)
利用位运算计算二进制下每一位为1的次数,若次数是3的倍数,则表明ans在该位上为0反之为1。
解法2:位运算优化
思路与解法1类似,但更为巧妙。
原解析写的更清楚,详见具体解析:
代码:
#法一
class Solution:
def singleNumber(self, nums: List[int]) -> int:
cnt = [0]*32
for i in nums:
for j in range(0,32):
if i&(1<<j):
cnt[j]+=1
ans = 0
for i in range(0,32):
if cnt[i]%3!=0:
ans += 1<<i
return ans
#法二
class Solution:
def singleNumber(self, nums: List[int]) -> int:
ones, twos = 0, 0
for num in nums:
ones = ones ^ num & ~twos
twos = twos ^ num & ~ones
return ones
以上是关于剑指 Offer 56 - I 至 56 - II 数组中数字出现的次数 I && II 题解的主要内容,如果未能解决你的问题,请参考以下文章
剑指 Offer 56 - II. 数组中数字出现的次数 II
剑指 Offer 56 - II. 数组中数字出现的次数 II
剑指offer位运算56 - II. 数组中数字出现的次数 II
LeetCode(剑指 Offer)- 56 - II. 数组中数字出现的次数 II