这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战
三周攻克数据结构,是LeetCode上的一个学习活动,每天三道题,用三周时间重温典型数据结构。
只出现一次的数字
-
不考虑时间复杂度与空间复杂度的解法
- 使用集合存储数字,如果集合中有该数字则删除,如果集合中没有该数字则添加。最后集合剩下的数字就是只出现一次的数字。
- 使用哈希表存储数字和数字出现的次数,最后遍历哈希表得到只出现一次的数字。
- 使用集合存储出现过的数字,计算数组的和以及集合的和,两个和的差值就是只出现一次的数字。
-
使用位运算
异或运算
a ^ 0 = a;
a ^ a = 0;
a ^ a ^ b = b;
通过将数组的所有数字进行异或运算,最后结果就是只出现一次的数字,时间复杂度为O(n),空间复杂度为O(1) 。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ret = 0;
for(int x : nums){
ret ^= x;
}
return ret;
}
};
多数元素
使用哈希表,存储每个元素以及出现的次数。对于哈希映射中的每个键值对,键表示一个元素,值表示该元素出现的次数。为了省去最后遍历哈希表的时间,可以在将元素加入哈希表时维护最多次出现的值。
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int, int> counts;
int majority = 0, cnt = 0;
for (int num: nums) {
++counts[num];
if (counts[num] > cnt) { //记录当前最多次出现的元素及出现的次数
majority = num;
cnt = counts[num];
}
}
return majority;
}
};
三数之和
使用排序+双指针的方法,降低时间复杂度。
- 首先对数组进行排序,排序后固定一个数 nums[i],再使用左右指针指向 nums[i]后面的两端,数字分别为 nums[L] 和 nums[R],计算三个数的和 sum 判断是否满足为 00,满足则添加进结果集
- 如果 nums[i]大于 00,则三数之和必然无法等于 00,结束循环
- 如果 nums[i] == nums[i-1],则说明该数字重复,会导致结果重复,所以应该跳过
- 当 sum == 0 时,nums[L] == nums[L+1] 则会导致结果重复,应该跳过,L++
- 当 sum == 0 时,nums[R] == nums[R-1] 则会导致结果重复,应该跳过,R--
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
for (int first = 0; first < n; ++first) {
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
int third = n - 1;
int target = -nums[first];
for (int second = first + 1; second < n; ++second) {
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
while (second < third && nums[second] + nums[third] > target) {
--third;
}
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
ans.push_back({nums[first], nums[second], nums[third]});
}
}
}
return ans;
}
};