1. 只出现一次的数字 I
题目描述:给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。你必须设计并实现线性时间复杂度(O(n))的算法来解决此问题,且该算法只使用常量额外空间(O(1))。
示例 1 :
输入:nums = [2,2,1]
输出:1
示例 2 :
输入:nums = [4,1,2,1,2]
输出:4
示例 3 :
输入:nums = [1]
输出:1
提示:
1 <= nums.length <= 3 * 104
-3 * 104 <= nums[i] <= 3 * 104
除了某个元素只出现一次以外,其余每个元素均出现两次。
题目链接:link
答:解题思路:非空数组中除一个元素出现一次外,其余元素均出现两次。由于相同的数异或为0,而其他数与0异或不变。所以,遍历数组把所有数异或一遍,出现两次的数都异或为0了,则结果为只出现一次的元素。
代码如下: 由于作者最近在学习STL,所以代码中使用的都是迭代器,大家看不习惯可以点击链接看别的代码。
class Solution {
public:
int singleNumber(vector<int>& nums) {
// 所需变量
int key = 0; // 存储只出现一次的数
// 使用迭代器遍历数组,每个元素相互亦或
vector<int>::iterator begin = nums.begin();
vector<int>::iterator end = nums.end();
while (begin != end)
{
// 当前元素亦或
key ^= *begin;
// 下一个元素
++begin;
}
// 输出
return key;
}
};
2. 只出现一次的数字 II
题目描述:给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。你必须设计并实现线性时间复杂度的算法(O(n))且使用常数级空间(O(1))来解决此问题。
示例 1:
输入:nums = [2,2,3,2]
输出:3
示例 2:
输入:nums = [0,1,0,1,0,1,99]
输出:99
提示:
1 <= nums.length <= 3 * 104
-231 <= nums[i] <= 231 - 1
nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次
题目链接: link
答:解题思路:首先,数组的类型为int,所以每个数有32位,而其他数都是3对出现的,所以32位中,为1的位的次数要么是3n,要么是3n+1,而出现次数为3n+1则是所求只出现1次的数的为1位,出现次数为3n则是所求只出现1次的数的为0位。然后,通过与1异或还原为1的位。
代码如下:
class Solution {
public:
int singleNumber(vector<int>& nums) {
// 创建一个包含32个元素的int数组,遍历数组存储32位数中每位上1的出现次数
int times_per_bit[32] = { 0 };
int size = nums.size();
for (int i = 0; i < size; ++i)
{
// 存储每位数1出现的次数
for (int j = 0; j < 32; ++j)
{
// 判断本位是否为1
if (nums[i] & (1 << j))
{
// 次数加1
++times_per_bit[j];
}
}
}
// 遍历每位为1的次数数组,出现次数不是3n的倍数的位,为所求元素为1的位
int key = 0;
for (int i = 31; i >= 0; --i)
{
// 还原所求值
if (times_per_bit[i] % 3)
key = key ^ (1 << i);
}
return key;
}
};
3. 只出现一次的数字 III
题目描述:给你一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。你必须设计并实现线性时间复杂度的算法且仅使用常量额外空间来解决此问题。
示例 1:
输入:nums = [1,2,1,3,2,5]
输出:[3,5]
解释:[5, 3] 也是有效的答案。
示例 2:
输入:nums = [-1,0]
输出:[-1,0]
示例 3:
输入:nums = [0,1]
输出:[1,0]
提示:
2 <= nums.length <= 3 * 104
-231 <= nums[i] <= 231 - 1
除两个只出现一次的整数外,nums 中的其他数字都出现两次
题目链接: link
答:解题思路:把数组中所有数异或,结果为只出现一次的两个数的异或。然后遍历结果的32位,找出为1的位,则该两个数在此位上一个为0,一个为1,由此把数组分成两部分,然后只出现一次的两个数被分开。两部分分别进行异或,最后的结果就是所求两数。
代码如下:
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
// 把数组中所有数异或,结果为只出现一次的两个数的异或
int result = 0;
// 范围for
for (auto val : nums)
{
result ^= val;
}
// 遍历结果的32位数,其中为1的位,就是只出现一次的两个数相异的位
int i;
for (i = 0; i < 32; ++i)
{
if (result & (1 << i))
break;
}
// 以相异的位为分界,把数组分成两组,这两组分别异或,结果为所求两数
int val1 = 0;
int val2 = 0;
for (auto val : nums)
{
if (val & (1 << i))
val1 ^= val;
else
val2 ^= val;
}
// 使用vector返回
vector<int> ret;
ret.push_back(val1);
ret.push_back(val2);
return ret;
}
};