242.有效的字母异位词
学透哈希表,数组使用有技巧!Leetcode:242.有效的字母异位词
思路
因为字母一共有26个,并且字母的ascii码也是连续的,集合大小有限,就可以考虑用数组实现哈希表,(如果要求集合内没有重复值,可以用set,集合内元素一个key对应一个value,可以用map),初始化一个长度尾26的数组,其中索引下标为0的元素对应于a,索引下表为1对应元素b以此类推(具体怎么对应?只需要用当前遍历到的元素进去'a'即可对应上,例如出现字母b则减去a就相当于a与b的ascii码相减,结果为1)然后遍历字符串s,统计s中各个元素出现的次数,然后遍历字符串t,然后对t中出现的元素在数组元素对应位置做相应的减法,最后遍历哈希表,如果有非零元素说明不是有效字母异位词,如果全0说明是有效字母异位词。
代码实现:
class Solution {
public:
bool isAnagram(string s, string t) {
int hashtable[26]={0};
for(int i=0;i<s.size();i++)
hashtable[s[i]-'a']++;
for(int i=0;i<t.size();i++)
hashtable[t[i]-'a']--;
for(int i=0;i<26;i++)
if(hashtable[i]!=0)return false;
return true;
}
};
时间复杂度o(n)空间复杂度o(1)
349.两个数组的交集
学透哈希表,set使用有技巧!Leetcode:349. 两个数组的交集
方法一:使用数组哈希表
数组的交集,不是子集要搞清楚,也就值要统计数组2中和数组1中共同出现过的元素。使用数组哈希表,因为题目表示两个数组的大小不超过1000,长度固定且不大,所以可以使用数组哈希表
代码实现:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
bool hashtable[1002]={false};
unordered_set<int> result_set;//存放结果,使用set存储是为了给数组去重
for(int num:nums1)
hashtable[num]=true;
for(int num:nums2){
if(hashtable[num])
result_set.insert(num);
}
return vector<int>(result_set.begin(),result_set.end());
}
方法二:使用set
显然是要判断数组2中的元素有没有在数组1中出现过,由此可以得出结论,使用哈希表做,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。但是哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。
为啥使用set,因为要求结果里没有重复值,也就是说要去重,所以使用set。
代码实现:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
//方法二,使用set做
unordered_set<int> result_set;
unordered_set<int> nums_set(nums1.begin(),nums1.end());
for(int num:nums2){
if(nums_set.find(num)!=nums_set.end())//为啥是不等于的时候是找到元素了,注意这里条件是什么,nums_ set的find迭代器,如果迭代器一直找到nums_end()了都没有找到num说明nums_set里没有这个元素,也就是他俩相等,不等于说明找见了。
result_set.insert(num);
}
return vector<int>(result_set.begin(),result_set.end());
}
};
202.快乐数
思路
就是349题穿了一个马甲,本题和上一题几乎一样,只需要判断个数位平方和出现过没有(如果出现过则肯定是无限循环,直接返回false),因此不需要重复记录,使用set。
代码实现:
class Solution {
public:
int divied(int n){
int result=0;
while(n){
result+=(n%10)*(n%10);
n=n/10;
}
return result;
}
bool isHappy(int n) {
unordered_set<int> sum;
while(sum.find(1)==sum.end()){
n=divied(n);
if(sum.find(n)!=sum.end()) return false;
sum.insert(n);
}
return true;
}
};
1.两数之和
梦开始的地方,Leetcode:1.两数之和,学透哈希表,map使用有技巧!
方法一:暴力解法
遍历所有可能的数组,时间复杂度爆炸
代码实现:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_set<int> result;
//暴力解法
for(int i=0;i<nums.size();i++){
for(int j=i+1;j<nums.size();j++){
int sum=nums[i]+nums[j];
if(sum==target) {
result.insert(i);
result.insert(j);
}
}
}
return vector<int>(result.begin(),result.end());
}
时间复杂度o(n^2)空间复杂度o(1)
方法二:使用map
四个重点1.为什么想动用哈希表? 因为要查target与当前遍历元素的差值,之前是否遍历过,查找一个元素是否出现过, 用哈希表
2.为什么想到用map?因为不仅仅要查元素的值。还要其对应的下标,只有map可以
3.map是用来存什么的? 存遍历过的元素与对应的下标
4.map的key和value分别存什么? 既然要对比这个元素是否出现过,对比的是key,value则存对应的下标
代码实现:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_set<int> result;
unordered_map<int,int> map;
for(int i=0;i<nums.size();i++){
auto iter=map.find(target-nums[i]);//遍历当前元素,找差值是否出现过
if(iter!=map.end()){
return {iter->second,i};
}
//没有出现过,就把当前访问的元素和下标加进去,以便后续查找
map.insert(pair<int,int>(nums[i],i));
}
return {};//没有找到 返回空数组
}
时间复杂度o(n)空间复杂度o(n)
总结
今天的四个题都有难度,算是吧哈希表的三种类型给入了门了,
当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
但是哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。