349. 两个数组的交集
方法一:哈希表
思路
用一个哈希表存储第一个数组出现的元素,然后遍历第二个数组查看是否在第一个数组里出现过,注意的点是返回的数组的元素是唯一的,所以要注意判断是否是唯一的。由于题目说明了数组的元素的取值介于0到1000,所以也可以使用数组来代替哈希表记录。
- 时间复杂度: O ( n + m ) O(n+m) O(n+m)
- 空间复杂度: O ( c ) O(c) O(c)
C++代码
// 使用哈希表记录
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int, int> hashMap;
vector<int> res;
for (int& n1 : nums1) ++hashMap[n1];
for (int& n2 : nums2) {
if (hashMap.find(n2) != hashMap.end() && hashMap[n2] > 0) {
res.push_back(n2);
hashMap[n2] *= -1;
}
}
return res;
}
};
// 使用数组记录
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
int record[1001] = {0};
vector<int> res;
for (int& n1 : nums1) record[n1] = 1;
for (int& n2 : nums2) {
if (record[n2] == 1) {
res.push_back(n2);
--record[n2];
}
}
return res;
}
};
方法二:排序+遍历
思路
先把两个数组进行排序,然后再同时遍历两个数组。
- 时间复杂度: O ( n log n + m log m ) O(n\log{n} + m\log{m}) O(nlogn+mlogm)
- 空间复杂度: O ( log n + log m ) O(\log{n} + \log{m}) O(logn+logm)
C++代码
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
int idx1 = 0;
int idx2 = 0;
int size1 = nums1.size();
int size2 = nums2.size();
vector<int> res;
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
while (idx1 < size1 && idx2 < size2) {
if (nums1[idx1] == nums2[idx2]) {
if (res.size() == 0 || res.back() != nums1[idx1]) res.push_back(nums1[idx1]);
++idx1;
++idx2;
} else if (nums1[idx1] < nums2[idx2]) ++idx1;
else ++idx2;
}
return res;
}
};
看完讲解的思考
无。
代码实现遇到的问题
无。
350. 两个数组的交集 II
方法一:哈希表
用时:3m5s
思路
与上一题差不多。
- 时间复杂度: O ( m + n ) O(m+n) O(m+n)。
- 空间复杂度: O ( c ) O(c) O(c)。
C++代码
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int, int> hashMap;
vector<int> res;
for (int& n1 : nums1) ++hashMap[n1];
for (int& n2 : nums2) {
if (hashMap.find(n2) != hashMap.end() && hashMap[n2] > 0) {
res.push_back(n2);
--hashMap[n2];
}
}
return res;
}
};
方法二:排序+遍历
用时:3m8s
思路
与上一题类似。
- 时间复杂度: O ( m log m + n log n ) O(m\log{m}+n\log{n}) O(mlogm+nlogn)。
- 空间复杂度: O ( log m + log n ) O(\log{m} + \log{n}) O(logm+logn)。
C++代码
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
int idx1 = 0;
int idx2 = 0;
int size1 = nums1.size();
int size2 = nums2.size();
vector<int> res;
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
while (idx1 < size1 && idx2 < size2) {
if (nums1[idx1] == nums2[idx2]) {
res.push_back(nums1[idx1++]);
++idx2;
} else if (nums1[idx1] < nums2[idx2]) ++idx1;
else ++idx2;
}
return res;
}
};
看完讲解的思考
无。
代码实现遇到的问题
无。
202. 快乐数
方法一:哈希表
用时:13m30s
思路
如果n不是快乐数,那么n在变换的过程中一定会出现重复的数字,故使用哈希表记录出现过的数字,当重复时则返回false。
- 时间复杂度: O ( log n ) O(\log{n}) O(logn),此处的log是以10为底的,主要是计算每个位数的值的时间复杂度。
- 空间复杂度: O ( log n ) O(\log{n}) O(logn)。具体推导见题解。
C++代码
class Solution {
public:
bool isHappy(int n) {
unordered_set<int> hashSet;
int sum;
while (true) {
hashSet.insert(n);
sum = getSum(n);
if (sum == 1) return true;
else if (hashSet.find(sum) != hashSet.end()) return false;
n = sum;
}
}
int getSum(int n) {
int sum = 0;
while (n) {
sum += (n % 10) * (n % 10);
n /= 10;
}
return sum;
}
};
方法二:快慢数
思路
判断是否有循环,类似于判断链表是否有环,可以使用两个数字,一个数字每次更新一步,一个数字每次更新两步,若存在循环,则两个数字一定会相遇。
- 时间复杂度: O ( log n ) O(\log{n}) O(logn)
- 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
bool isHappy(int n) {
int slow = n;
int fast = n;
while (true) {
slow = getSum(slow);
fast = getSum(getSum(fast));
if (slow == 1) return true;
if (slow == fast) return false;
}
}
int getSum(int n) {
int sum = 0;
while (n) {
sum += (n % 10) * (n % 10);
n /= 10;
}
return sum;
}
};
看完讲解的思考
为什么循环过程数字一定不会无限变大,而是会变成1或者循环?
当每个位数都取最大值9时的变换:9 => 81,99 => 162,999 => 243,…
观察可知,即使都取最大值9,当位数大于等于2时,数字变换是会变小的,所以不可能无限增大。所以一定会循环。
代码实现遇到的问题
不知道如何获取一个数字的每个位数上的值,一开始用的方法是转换成字符串,再获取到每个字符,再转换成数字,过于麻烦,实际上可以通过循环求余得到。
最后的碎碎念
这几天一直在忙论文的rebuttal,时间紧任务重,就没时间刷题了,停了几天。现在rebuttal搞完了,继续刷,10天没刷,还好手感还在。