leetcode200题之哈希表(二)

1. 有效的字母异位词

法一:排序

通过将 s 的字母重新排列成 t 来生成变位词。因此,如果 t 是 s 的变位词,对两个字符串进行排序将产生两个相同的字符串。此外,如果 s 和 t 的长度不同,t 不能是 s 的变位词,我们可以提前返回。

法二:哈希表

为了检查 t 是否是 s 的重新排列,我们可以计算两个字符串中每个字母的出现次数并进行比较。因为 s 和 t 都只包含 a-z 的字母,所以一个简单的 26 位计数器表就足够了。

我们需要两个计数器数表进行比较吗?实际上不是,因为我们可以用一个计数器表计算 s 字母的频率,用 t 减少计数器表中的每个字母的计数器,然后检查计数器是否回到零。

class Solution {
public:
    bool isAnagram(string s, string t) {
        vector<int> hash(26);
        if(s.size()!=t.size())  return false;
        for(int i=0; i<s.size(); i++){
            hash[s[i]-'a']++;
            hash[t[i]-'a']--;
        }
        for(auto num:hash){
            if(num!=0)  return false;
        }
        return true;
    }
};

2. 字母异位词分组

题目:https://leetcode-cn.com/problems/group-anagrams/

思路: 

(1)排序+哈希:先遍历strs,对每个string进行排序,异位词的排序结果是一样的,在map中的key值也就一样,然后在map中添加对应的vector,再将vector逐个添加到res中

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
         vector<vector<string>> res;
        unordered_map<string, vector<string>> mp;
        for(auto& str:strs){
            string t=str;
            sort(t.begin(), t.end());
            mp[t].push_back(str);
        }
        for(auto i:mp){
            res.push_back(i.second);
        }
        return res;   
    }
};

3. 前K个高频元素

  1. 借助 哈希表 来建立数字和其出现次数的映射,遍历一遍数组统计元素的频率
  2. 维护一个元素数目为 k 的最小堆
  3. 每次都将新的元素与堆顶元素(堆中频率最小的元素)进行比较
  4. 如果新的元素的频率比堆顶端的元素大,则弹出堆顶端的元素,将新的元素添加进堆中
  5. 最终,堆中的 k 个元素即为前 k 个高频元素

补充priority_queue相关知识:

定义:priority_queue <Type, Container, Functional >
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆 

//升序队列  (小根堆)
priority_queue <int,vector<int>,greater<int> > q;
//降序队列  (大根堆)   默认为大根堆
priority_queue <int,vector<int>,less<int> >q; 

//greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)
class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> mp;
        for(auto num:nums){
            ++mp[num];
        }
        priority_queue< pair<int,int>, vector<pair<int, int>>, greater<pair<int,int>>> pq;
        for(auto i:mp){
            if(pq.size()==k){
                if(i.second > pq.top().first){
                    pq.pop();
                    pq.push(make_pair(i.second,i.first));
                }
            }
            else pq.push(make_pair(i.second,i.first));  //先比较的是前一个,所以second在前
        }
        vector<int> res;
        while(!pq.empty()){
            res.push_back(pq.top().second);
            pq.pop();
        }
        return vector<int>(res.rbegin(), res.rend());
    }
};

4. 多数元素(leetcode 169题)

法一:哈希,很简单,不做阐述,直接看代码

法二:摩尔投票:

当遇到与candidate相同的数,则票数count ++,否则票数count --。当票数count为0时,更换候选人。

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        /*哈希
        unordered_map<int, int> mp;
        for(auto num:nums){
            ++mp[num];
            if(mp[num]>nums.size()/2){
                return num;
            }
        }
        return -1;
        */
        /*摩尔投票*/
        int candidate, count=0;
        for(auto num: nums){
            if(count==0)  candidate=num;
            if(num==candidate)  count++;
            else count--;
        }
        return candidate;
    }
};

5. 重构字符串

  1. 记录每个字母在字符串中的数量(哈希表)
  2. 若存在字母的数量大于一半则无法构造,直接返回空字符串(奇偶有别)
  3. 根据字母数量降序排序(插入优先队列,以字母数量较大优先级较高,类似于大顶堆)
  4. 按照字母数量降序顺序,当队列不空时,依次按照堆顶元素,隔着往原字符串插入当前字符,下标从 0 开始,每次插入下标 +2,当超过数组大小时,变为 1。(对半达底后折回)
class Solution {
public:
    string reorganizeString(string S) {
        unordered_map<char,int> mp;
        for(auto s:S){
            ++mp[s];
            if(mp[s]>(S.size()+1)/2){
                return "";
            }
        }
        priority_queue<pair<int,char>> pq;      //大顶堆
        for(auto i:mp){
            pq.push(make_pair(i.second, i.first));
        }

        string res=S;
        int i=0;
        while(!pq.empty()){
            char ch=pq.top().second;
            int cnt=pq.top().first;
            pq.pop();
            while(cnt){
                if(i>=S.size())  i=1;
                res[i]=ch;
                i += 2;  //间隔着放
                cnt--; 
            }
        }
        return res;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值