242.有效的字母异位词
- 题目链接:242.有效的字母异位词
- 独立思路:用map表记录字符串s中出现过的字母及其出现次数。再遍历字符串t中的每个字符x,若x存在于mp中且mp[x]>0,则将mp[x]--。若二者为同字母异序词,则最终mp会全为0
- 时间复杂度:O(n)
- 空间复杂度:O(n)
(另解:先排序再return s==t
。比较简单,不写了)
//想法:新建map表,key值记录字母,value值记录字母出现的次数,如果两个字符串的key、value值完全一样
//则为同字母异序词
class Solution {
public:
bool isAnagram(string s, string t) {
map<char, int> mp;
int n1 = s.size();
int n2 = t.size();
if(n1 != n2)
return false;
for(int i = 0; i < n1; i++){ //遍历字符串s
mp[s[i]]++;
}
for(int i = 0; i < n2; i++){ //遍历字符串t
if(mp.find(t[i]) != mp.end() && mp[t[i]] > 0)
mp[t[i]]--;
else
return false;
}
return true;
}
};
//同种思路,更简洁的版本
class Solution {
public:
bool isAnagram(string s, string t) {
map<char, int> mp;
if(s.size() != t.size())
return false;
for(int i = 0; i < s.size(); i++){
mp[s[i]]++;
mp[t[i]]--;
}
for(const auto &x : mp) //检查mp是否全空了
if(x.second != 0)
return false;
return true;
}
};
349. 两个数组的交集
- 题目链接:349. 两个数组的交集
- 独立思路:遍历nums1,用set记录其中的元素(方便用find)。再遍历nums2,若其中元素存在于set,则存进vector类型的ans
- 问题(已解决):用vector类型存储数组,会存到重复的元素!比如nums[]中前后出现了多次的'2'这个元素,2也存在于visited中,则2会被多次存入ans数组。
解决方法:ans也用set类型存储,这样不会存储重复的元素。最后再转换为vector数组并返回
- 时间复杂度:O(m+n)
- 空间复杂度:O(m+n)
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
//vector<int> ans; 不能用vector类型存储!不然会存入重复元素
unordered_set<int> ans;
unordered_set<int> visited(nums1.begin(), nums1.end());
//记录nums1中出现过的元素,且只存储一次(set不存重复值)
for(int num : nums2){
if(visited.find(num) != visited.end())
ans.insert(num);
}
return vector<int> (ans.begin(), ans.end());
}
};
- 独立思路2(先排序、再双指针):nums1和nums2先排序,再逐个元素比较。相等则加入ans,且两个指针均右移,否则小的那个指针移动
- 问题(已解决):一开始把排序写成
nums1.sort()
,结果编译出错了。忘记了vector类型的排序是sort(nums.begin(), nums.end())
- 时间复杂度:O(nlog2n+mlog2m)
- 空间复杂度:O(log2n+log2m)
//想法2:先排序再比较
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
int n1 = nums1.size();
int n2 = nums2.size();
unordered_set<int> ans;
int i = 0, j = 0;
while(i < n1 && j < n2){
if(nums1[i] == nums2[j]){
ans.insert(nums1[i]);
i++; j++;
}else if(nums1[i] < nums2[j]){
i++;
}else{
j++;
}
}
return vector<int>(ans.begin(), ans.end());
}
};
202. 快乐数
- 题目链接:202. 快乐数
- 独立思路:❌ 没想出来,明天回来做。重点要从数学意义上理解, 计算正整数是否为开心数的过程不可能到无限大,只会有两种情况:① 是开心数 ②进入循环
- 官方题解1:用哈希表记录每个数的squareSum值,当该squareSum值没有在哈希表中出现过,则继续求其squareSum值,直到①出现过 ②最终squareSum为1,跳出循环。判断最终只是否为1即可
- 时间复杂度:O(logn)
- 空间复杂度:O(logn)
- 位数运算:对于一个数字 n,每次计算平方和涉及的操作次数与其位数成正比。位数可以近似表示为 log(n),因为每增加一位,数字大小增加一个数量级。
- 循环检测:理论上,这个过程可能会持续很长时间,但实际上,对于任何数字,要么最终达到1,要么很快进入一个已知的循环。这个循环的大小是固定的,因此这部分的时间复杂度可以被认为是常数时间,即 O(1)。
class Solution {
public:
int getSum(int n){
int sum = 0;
while(n > 0){
int digit = n%10; //取最低位
sum += digit*digit;
n = n/10; //n向右移1位(舍掉了最低位)
}
return sum;
}
bool isHappy(int n) {
unordered_set<int> visited;
while(n != 1 && visited.find(n) == visited.end()){ //n≠1且未在哈希表中出现过
visited.insert(n);
n = getSum(n);
}
return n == 1;
}
};
- 官方题解2:用快慢指针判断是否有循环,有循环时
slow==fast!=1
,无循环时slow==fast==1
- 时间复杂度:O(logn)
- 空间复杂度:O(1)
//解法2:快慢指针
class Solution{
public:
int getSquareSum(int n){
int sum = 0;
while(n > 0){
int digit = n%10;
sum += digit * digit;
n = n/10;
}
return sum;
}
bool isHappy(int n){
int slow = n;
int fast = n;
do{
slow = getSquareSum(slow);
fast = getSquareSum(fast);
fast = getSquareSum(fast);
}while(slow != fast); //slow=fast情况:①最终值为1 ②slow与fast碰到了(循环)
return slow == 1;
}
};
1.两数之和
- 题目链接:1.两数之和
- 独立思路:❌ 没想出来,map表的运用不够熟练
- 官方题解:用map表,first值存元素值,second值存下标。懂了!
- 时间复杂度:O(n)
- 空间复杂度:O(n)
class Solution{
public:
vector<int> twoSum (vector<int>& nums, int target){
map<int, int> m;
int x;
for(int i = 0; i < nums.size(); i++){
x = target-nums[i];
auto pos = m.find(x); //map的查找函数是查key值,所以要把具体数值当作key、下标当value存进去
if(pos != m.end()){ //哈希表mapm中存在key值为x的元素
return{(*pos).second, i};
}
m[nums[i]] = i;
}
return {};
}
};