代码随想录算法训练营第五天|Leetcode 242 有效的字母异位词,349 两个数组的交集,202 快乐数,1.两数之和
哈希理论基础
https://programmercarl.com/%E5%93%88%E5%B8%8C%E8%A1%A8%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html
收获:
当问题转换为判断一个元素是否再一个集合里时优先考虑哈希
Leetcode 242.有效的字母异位词
题目链接 LCR 032. 有效的字母异位词
文章链接 https://programmercarl.com/0242.%E6%9C%89%E6%95%88%E7%9A%84%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D.html
视频链接 https://www.bilibili.com/video/BV1YG411p7BA
思路
暴力可以做,但是主要是练一下哈希。这道题可以把‘a’-'z’映射成0-25即可,26的长度直接用数组存就好了,定义两个数组(也可以定义一个),分别记录每个串中的每个字符出现次数,再判断两个数组的每个值是否相等
代码
class Solution {
public:
bool isAnagram(string s, string t) {
vector<int> data1(26);//26个英文字母,只需要开辟26个数组单元就可以了
vector<int> data2(26);
if(s.length()!=t.length()){
return false;
}
for(char c:s){
data1[c-'a']++;//‘a’从0开始存储
}
for(char c:t){
data2[c-'a']++;
}
for(int i=0;i<26;i++){
if(data1[i]!=data2[i]){
return false;
}
}
return true;
}
};
Leetcode 349 两个数组的交集
题目链接 349. 两个数组的交集
文章链接 https://programmercarl.com/0349.%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86.html
视频链接 https://www.bilibili.com/video/BV1ba411S7wu
思路
和上道题思路差不多,定义一个record数组存储在nums1数组现过的数字(对应下标的值更新为1),再遍历nums2,把值为1的下标(代表在nums2中出现且在nums1中出现)用另一个数组存储起来。因为这道题给出了数组的值的范围为0-1000,所以可以用数组存储。如果没给出长度,那可以用集合来存,要存的内容不能有重复,而且不需要有顺序,所以这里用到的容器unordered_set的效率是最高的(底层实现为哈希)。
代码
- 数组
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
vector<int> result(1001,0);//结果数组
vector<int> record(1001,0);//记录数组
int index = 0;
for(int i=0;i<nums1.size();i++){
record[nums1[i]] = 1;//把nums1中出现过的数更新为1,代表已经出现过
}
for(int i=0;i<nums2.size();i++){
if(record[nums2[i]]==1){//在nums2中出现同时也在nums1中出现
result[index++] = nums2[i];//存下
record[nums2[i]] = 0;//防止重复的元素进入
}
}
result.resize(index);
return result;
}
};
- 集合(unordered_set)
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result;
unordered_set<int> data(nums1.begin(),nums1.end());//把nums1的元素全都存入unordered_set
for(int i=0;i<nums2.size();i++){
if(data.find(nums2[i])!=data.end()){
result.insert(nums2[i]);
}
}
vector<int> res(result.begin(),result.end());
return res;
}
};
Leetcode 202 快乐数
题目链接 202. 快乐数
文章链接 https://programmercarl.com/0202.%E5%BF%AB%E4%B9%90%E6%95%B0.html
思路
举个例子:37
发现不是快乐数的数会无限的循环,有点像反复经过一个轮次,当一个数已经出现过时,就说明开始了新的循环轮次,所以这道题就是判断一个数是否已经出现在先前出现的集合中,用哈希来做,长度不固定,可以没有顺序,且元素不重复,选择unordered_set,当每次计算后的每个数位平方和的数没出现过,就插入集合,出现过就不是快乐数
代码
class Solution {
public:
int calculate(int n){
int sum = 0;
while(n){
sum += (n%10)*(n%10);
n = n/10;
}//循环结束时,n为个位数
sum += n*n;
return sum;
}//计算每个数各个数位的平方和
bool isHappy(int n) {
unordered_set<int> data;
int res;
data.insert(n);
while(n!=1){
res = calculate(n);
if(data.find(res)==data.end()){
data.insert(res);//集合中没有这个元素,则插入
}else{
return false;//如果元素出现过,就说明这个数是每个轮次的开始,要无限循环下去了,不可能是快乐数
}
n = res;//每次更新n的值
}
return true;
}
};
Leetcode 1.两数之和
题目链接 1. 两数之和
文章链接 https://programmercarl.com/0001.%E4%B8%A4%E6%95%B0%E4%B9%8B%E5%92%8C.html
思路
看完题解之后,发现我的做法时间复杂度有点高了,原因是我用的multimap来存储,其底层使用红黑树实现,查询和增加删除的时间复杂度都是O(logn),所以我写的时间复杂度是(nlogn)。先写一下我的思路,这道题我翻译成判断target-nums[i]的值是否在集合内,用哈希做,所以我就要存数组所有的值,要求下标,所以要存的内容是(nums[i],i),故选择用map来存,因为我是先存,所以就有key值一样的情况,就想到了multimap来存储。遍历这个容器,如果target-nums[i]在容器内就返回下标,要注意需要加上下标不等的条件来应对键值相等的情况。
再说说题解的,题解用的unordered_map,其底层是用的哈希实现,查询和增加删除的时间复杂度都是O(1),代码总的时间复杂度为O(n)。遍历nums,一个一个存,用后面的数做nums[i];如果target-nums[i]在之前的集合已经出现过,返回下标。这就避免了键值相等存不进去的情况
- multimap
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
multimap<int,int> data;
vector<int> result(2,0);
for(int i=0;i<nums.size();i++){
data.insert(make_pair(nums[i],i));
}//先全部存入
for(auto it=data.begin();it!=data.end();it++){
result[0] = it->second;
//cout<<result[0]<<" ";
auto temp = data.find(target-it->first);
if(temp!=data.end()&&(it->second)!=(temp->second)){
result[1] = temp->second;
//cout<<result[1]<<endl;
break;
}
}
return result;
}
};
- unordered_map
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map <int,int> map;
vector<int> result(2);
for(int i = 0; i < nums.size(); i++) {
// 遍历当前元素,并在map中寻找是否有匹配的key
auto temp = map.find(target - nums[i]);
if(temp != map.end()) {
result[0] = temp->second;
result[1] = i;
return result;
}
// 如果没找到匹配对,就把访问过的元素和下标加入到map中
map.insert(make_pair(nums[i], i));
}
return {};
}
};