网站救助计划
1.为阅读体验,本站无任何广告,也无任何盈利方法,站长一直在用爱发电,现濒临倒闭,希望有能力的同学能帮忙分担服务器成本
2.捐助10元及以上同学,可添加站长微信lurenzhang888,备注捐助,网站倒闭后可联系站长领取本站pdf内容
3.若网站能存活下来,后续将会持续更新内容
题目描述
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
限制:
- 2 <= nums.length <= 10000
题解
(位运算,异或) O(n)
首先我们知道求数组中只出现一次的一个数字的求法,因为除了这个数其他数都出现了两次,所以将所有数异或起来的结果就是答案。
这道题目要求的是只出现一次的两个数字,我们需要想办法把它拆解成第一类问题
假设两个数字为 x、y
- 先将所有数异或起来的结果记为
sum = x ^ y
,因为其他数字都出现两次,它们异或的结果是 0 - 由于
x != y
则 x 和 y 不全为 0,所以 sum 必不为 0,那么 sum 的二进制表示中肯定有 1,且对于为 1 位,x 和 y 必然其中一个为 1,另一个为 0,否则异或的结果当前位不可能为 1,按照 sum 的二进制表示中最后一个 1(假设是第 k 位) 所有数划分为两个集合,一个集合中第 k 位全为 1,另一个集合中第 k 位全为 0,且 x 和 y 不在同一个集合 - 此时问题就转换成了求两个「数组中只出现一次的一个数字」,对两个集合分别异或起来,得到的就是 x 和 y
优化:只求一个集合的异或结果可以得到一个数 first (= x / y),而已知
sum = x ^ y
,则 first ^ sum 就是另一个数
时间复杂度
考虑最长时间就是遍历数组所花费的时间,时间复杂度为 O(n)。
空间复杂度
O(1)
C++ 代码
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int sum = 0;
for (auto x : nums) sum ^= x;
int t = sum & -sum; // t 表示 sum 的最后一个表示的二进制数,比如 100100,结果就是 100
int first = 0;
for (auto x : nums)
if (x & t) // 如果是 1,则分到和 first 一组
first ^= x;
return {first, sum ^ first};
}
};
Java 代码
class Solution {
public int[] singleNumbers(int[] nums) {
int sum = 0;
for (int x : nums) sum ^= x;
int t = sum & -sum; // t 表示 sum 的最后一个表示的二进制数,比如 100100,结果就是 100
int first = 0;
for (int x : nums) {
if ((x & t) != 0) { // 如果是 1,则分到和 first 一组
first ^= x;
}
}
return new int[]{first, sum ^ first};
}
}
Python 代码
class Solution:
def singleNumbers(self, nums: List[int]) -> List[int]:
xor_sum = 0
for x in nums:
xor_sum ^= x
t = xor_sum & -xor_sum # t 表示 xor_sum 的最后一个表示的二进制数,比如 100100,结果就是 100
first = 0
for x in nums:
if x & t: # 如果是 1,则分到和 first 一组
first ^= x
return [first, xor_sum ^ first]
本文由读者提供,Github地址:https://github.com/tonngw
点击面试手册,获取本站面试手册PDF完整版