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个高频元素
- 借助 哈希表 来建立数字和其出现次数的映射,遍历一遍数组统计元素的频率
- 维护一个元素数目为 k 的最小堆
- 每次都将新的元素与堆顶元素(堆中频率最小的元素)进行比较
- 如果新的元素的频率比堆顶端的元素大,则弹出堆顶端的元素,将新的元素添加进堆中
- 最终,堆中的 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. 重构字符串
- 记录每个字母在字符串中的数量(哈希表)
- 若存在字母的数量大于一半则无法构造,直接返回空字符串(奇偶有别)
- 根据字母数量降序排序(插入优先队列,以字母数量较大优先级较高,类似于大顶堆)
- 按照字母数量降序顺序,当队列不空时,依次按照堆顶元素,隔着往原字符串插入当前字符,下标从 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;
}
};