哈希知识一些记录:
- 虽然std::set、std::multiset 的底层实现是红黑树,不是哈希表,std::set、std::multiset 使用红黑树来索引和存储,不过给我们的使用方式,还是哈希法的使用方式,即key和value。所以使用这些数据结构来解决映射问题的方法,我们依然称之为哈希法。 map也是一样的道理。
- 哈希法也是牺牲了空间换时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。
- 做面试题目时遇到需判断一个元素是否出现过的场景也应该第一时间想到哈希法
#242 anagram multiset和unordered_map都试了下,看代码随想录答案用的array,容易的快题,
注意:
1 erase(key)not value
2 map[char]+=1; 如果一开始不存在,会自动创一个,并使用该类型的默认值进行初始化,比如0
3 string 不用管 \0,遍历可用 传统i++, itr++, auto ele:str
bool isAnagram(string s, string t) {
//multiset (repeated letter, no cnt)
multiset<char> setT;
for( int i =0; i<t.size();i++){
setT.insert(t[i]);
}
for( int i =0; i<s.size();i++){
if (setT.find(s[i]) != setT.end()){
setT.erase(setT.find(s[i]));
}
else{
return false;
}
}
return setT.empty();
bool isAnagram(string s, string t) {
//unordered_map (letter: cnt)
unordered_map<char, int> mapt;
for( int i =0; i<t.size();i++){
mapt[t[i]] += 1;
}
for (unordered_map<char, int>::iterator it = mapt.begin(); it != mapt.end(); ++it) {
cout << "Key: " << it->first << " Value: " << it->second << endl;
}
for( int i =0; i<s.size();i++){
if (mapt.find(s[i]) != mapt.end()){
mapt[s[i]] -= 1;
if(mapt[s[i]]==0){
mapt.erase(s[i]);
}
}
else{
return false;
}
}
return mapt.empty();
}
#349 intersection of array
这是标准思路,找到了直接push back vec
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
set<int> set1;
set<int> set2;
for (int i=0; i<nums1.size();i++){
set1.insert(nums1[i]);
}
for (int i=0; i<nums2.size();i++){
set2.insert(nums2[i]);
}
vector<int> res;
for(set<int>::iterator it=set1.begin();it!=set1.end();it++){
if(set2.find(*it)!=set2.end()){
res.push_back(*it);
}
}
return res;
}
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
set<int> set1;
set<int> set2;
for (int i=0; i<nums1.size();i++){
set1.insert(nums1[i]);
}
for (int i=0; i<nums2.size();i++){
set2.insert(nums2[i]);
}
vector<int> res;
for (auto it = set1.begin(); it != set1.end(); ) {
if (set2.find(*it) == set2.end()) {
it = set1.erase(it); // 删除元素,并更新迭代器
} else {
++it; // 移动到下一个位置
}
}
for (auto it = set1.begin(); it != set1.end(); it++) {
res.push_back(*it);
}
return res;
}
上面这是我一开始的思路:找到了不是的从nums1里删掉,最后num1统一转vec
关键易错点是 不能边itr 边 erase(itr),要做处理,因为erase了不用++了,它相当于自动++了
#202 快乐数
bool isHappy(int n) {
//brute force
//multiset
set<int> nset;
multiset<int> myset;
nset.insert(n);
while(1){
myset.clear();
while(n/10!=0){
int digit=n-(n/10)*10;
n/=10;
myset.insert(digit);
}
myset.insert(n);
n=0;
for(const auto& ele : myset) {
n+=ele*ele;
}
if(n==1){
return true;
}
if(nset.find(n)==nset.end()){
nset.insert(n);
}
else{
return false;
}
}
return false;
}
这题自己写的,不难,但时间复杂度不会分析,问了gpt也没看懂。代码随想录的答案好像跟我差不多,没仔细看,时间复杂度again不会分析
#1 两数之和 经典
折腾半天得有1小时,其实自己思路快对了,看了答案思路略微修改
我已经想到 1 必须用map 因为要index 2 pair(nums[i],i)是和正常相反的
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> mymap;
vector<int> res;
for (int i=0; i<nums.size(); i++){
auto it = mymap.find(target-nums[i]);
if(it != mymap.end()) {
res.push_back(it->second);
res.push_back(i);
break;
}
else{
mymap.insert(make_pair(nums[i],i));
}
}
return res;
}
没想到的点是不要一次放完,要边放边找,解决(3,3)那种case
今天其他学到的:
1.标答里两句要学:set和vec的互相转化,直接用begin end itr
unordered_set<int> nums_set(nums1.begin(), nums1.end());
return vector<int>(result_set.begin(), result_set.end());
2.set find(*it), erase(it)
map find(key) ,erase(key)
3 auto &, &代表是not copy,就是原来那个
然后多用c++11特性,比如 auto和 range for