难度:simple
本题同时也是《剑指offer 专项突击》的第4题。
problem
https://leetcode.cn/problems/WGki4K/
or
https://leetcode-cn.com/problems/single-number-ii/
给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。
示例 1:
输入:nums = [2,2,3,2]
输出:3
示例 2:
输入:nums = [0,1,0,1,0,1,100]
输出:100
提示:
1 <= nums.length <= 3 * 104
-231 <= nums[i] <= 231 - 1
nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次
进阶:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
初步解法
很直观的想法,就是用python的字典,有这个键就 对值加1,没有就新增键。最后看那个key的值是1.
class Solution:
def singleNumber(self, nums) -> int:
dict= {}
for i in range(len(nums)):
if not nums[i] in dict.keys():
dict[nums[i]]=1
else:
dict[nums[i]]+=1
for k in dict.keys():
if dict[k]==1:
return k
优化(可能是蠢化。。。)
考虑另一个问题:
给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 2 次 。请你找出并返回那个只出现了一次的元素。
注意到:
- 所有数异或(^)自己的结果都是0.
- 也就是说一个数和自身异或偶数次还是0.
- 如果一个数组只有某个元素出现奇数次,其余元素出现偶数次,直接对整个数组每个元素异或就能找出出现奇数次的元素。
class Solution:
def singleNumber(self, nums) -> int:
res = nums[0]
for i in range(1,len(nums)):
res = nums[i] ^ res
return res
更广泛的:
如果数组中只有一个数字出现m次,其余数字都出现n次。找出唯一出现m次的那个数字。假设m不能被n整除。
所有数字的第i个数位的和能被n整除,那么出现m次的数字的第 i 位为0;否则为 1.
注意到:
- **一个数二进制表示的右起第 i i i 位可以用
- ( n u m > > i ) & 1 (num>>i)\&1 (num>>i)&1得到。**
- eg. 6:‘110’, (6>>2)&1=1,‘110’右移2位是‘…001’,与1与得到1.
这里有个问题是二进制以补码的形式存在,对于负数就变了。
比如 -5,补码为:
1111 1111 1111 1111 1111 1111 1111 1011
如果是用上面的式子把每一位存下来,这个32位二进制要再求一次补码才是结果。因为int(''11111111111111111111111111111100'',2)
得到4294967292
,而不是我们想要的 -4
因此要自己写一下转补码的。
完整代码
class Solution:
def singleNumber(self, nums) -> int:
# dict= {}
# for i in range(len(nums)):
# if not nums[i] in dict.keys():
# dict[nums[i]]=1
# else:
# dict[nums[i]]+=1
# for k in dict.keys():
# if dict[k]==1:
# return k
# 只有一个数出现奇数次,其余数出现奇数次,找出这个数
# res = nums[0]
# for i in range(1,len(nums)):
# res = nums[i] ^ res
# return res
'''
如果数组中只有一个数字出现m次,
其余数字都出现n次。找出唯一出现m次的那个数字。假设m不能被n整除。
'''
res = [0]*32
for i in range(len(nums)):
for k in range(32):
res [k] += (nums[i]>>k)&1
for k in range(32):
res[k]=res[k]%3
res.reverse()
if res[0]==1:
sign = -1
for k in range(32):
if res[k] == 1:
res[k] = 0
else:
res[k]=1
else:
sign = 1
# print(res)
res = ''.join(list(map(str, res)))
if sign ==-1:
res = (int('0'+res[1:],2)+1) * sign
else:
res = int('0'+res[1:], 2)
return res
if __name__ =='__main__':
so = Solution()
nums = [-2,-2,1,1,4,1,4,4,-4,-2]
# nums = [2,2,1,1,4,1,4,4,4,2]
# nums = [-2,-2,3]
print(so.singleNumber(nums))