预备知识
1.哈希表:给定表M,存在函数f(key),对任意的关键字值key,代入函数后若能得到包含该关键字的表中地址,称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
2.字符哈希
统计字符个数,字符为下标【key】,个数为值【value】
3.哈希表排序整数
数组做哈希,下标为整数,自动排序
4.任意元素的映射
利用哈希函数,转换为整数,再对表长取余
5.发生冲突
6.拉链法解决冲突,构造哈希表【指针数组】【头插法】
7.哈希map与STL map
一,最长回文串
LeetCode 409. Longest Palindrome
1.用数组实现哈希:即下标为key,对应的值为value
2.是否有中心点,及其计算,比较讨巧
class Solution {
public:
int longestPalindrome(string s) {
int char_map[128]={0};
int max_length=0;
int flag=0;//是否有中心点
for(int i=0;i<s.length();i++){
char_map[s[i]]++;//利用整数的数组下标实现字符哈希,统计字符个数
}
for(int i=0;i<128;i++){
if(char_map[i]%2==0){
max_length+=char_map[i];
}
else{
max_length+=char_map[i]-1;//如果是奇数,可以有中心点,且舍去一个
flag=1;
}
}
return max_length+flag;
}
};
作者:xia-mu-lao-zhang-ren
链接:https://leetcode-cn.com/problems/longest-palindrome/solution/zui-chang-hui-wen-zi-chuan-by-xia-mu-lao-vknq/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
二,词语模式
1.根据空格划分单词
2.建立【字符串和字符】的映射
3.建立映射与否,字符是否使用过,是否不够或多余
4.没有映射就添加一个,有就继续往后添加,通过if实现此功能
class Solution {
public:
bool wordPattern(string pattern, string s) {
map<string,char>word_map;//单词-字符
char used[128]={0};
string word;//临时保存拆分的单词
int pos=0;//当前指向pattern的字符
s.push_back(' ');//s尾部追加一个空格,使得遇到空格拆分单词,无需特殊处理了
for(int i=0;i<s.length();i++){
if(s[i]==' '){//遇到空格,即拆分一个新单词
if(pos==pattern.length()){//pos走到头了,length=3,[0,1,2]
return false;
}
//若单词没有出现在哈希映射中
if(word_map.find(word)==word_map.end()){
if(used[pattern[pos]]){//如果当前字符已使用
return false;
}
word_map[word]=pattern[pos];//如果未使用,新加映射
used[pattern[pos]]=1;
}
//若单词出现在哈希映射中
else{
if(word_map[word]!=pattern[pos]){
return false;
}
}
//完成一个单词的插入和查询后,清空word,指针迁移
word="";
pos++;
}
else{
word+=s[i];//划分单词
}
}
if(pos!=pattern.length()){
return false;//有多余的pattern字符
}
return true;
}
};
作者:xia-mu-lao-zhang-ren
链接:https://leetcode-cn.com/problems/word-pattern/solution/dan-ci-gui-lu-by-xia-mu-lao-zhang-ren-qt1f/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
三,同字符词语分组
1.颠倒字母顺序就是【字符数相同】
2.怎样建立映射,排好序的字符,字符数量
3.有的就加入,没有的就新加映射
方法一,以内部进行排序的各个单词为 key
class Solution {
public:
//一个字符,映射一个字符数组
//各个字符数量相同的字符串
//若str未未出出现现在anagram中,设置str到一个空字符串向量的映射。
vector<vector<string>> groupAnagrams(vector<string>& strs) {
map<string,vector<string> >anagram;
vector<vector<string> >result;
for(int i=0;i<strs.size();i++){//遍历各个单词
string str=strs[i];//临时保存该单词
sort(str.begin(),str.end());
if(anagram.find(str)==anagram.end()){//若str未未出出现现在anagram中,设置str到一个空字符串向量的映射。
vector<string> item;
anagram[str]=item;
}
anagram[str].push_back(strs[i]); //在对应的字符串向量中push结果【 anagram[str]指的是vector<string>】
}
map<string,vector<string> >::iterator it;
for(it=anagram.begin();it!=anagram.end();it++){
result.push_back((*it).second);
}
return result;
}
};
作者:xia-mu-lao-zhang-ren
链接:https://leetcode-cn.com/problems/group-anagrams/solution/zi-mu-yi-wei-ci-fen-zu-by-xia-mu-lao-zha-l1l5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
方法二:以26个字母的字符数量为key
void change_to_vector(string &str,vector<int>&vec){
for(int i=0;i<26;i++){
vec.push_back(0);
}
for(int i=0;i<str.length();i++){
vec[str[i]-'a']++;//将str中的字符串各个字符个数进行统计并存入vec中
}
}
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
map<vector<int> ,vector<string> >anagram;
vector<vector<string> >result;
for(int i=0;i<strs.size();i++){
vector<int>vec;
change_to_vector(strs[i],vec);
if(anagram.find(vec)==anagram.end()){
vector<string>item;
anagram[vec]=item;
}
anagram[vec].push_back(strs[i]);
}
map<vector<int>,vector<string> >::iterator it;
for(it=anagram.begin();it!=anagram.end();it++){
result.push_back((*it).second);
}
return result;
}
};
四,无重复字符的最长子串
LeetCode 3. Longest Substring Without Repeating Characters
滑动窗口
1.用字符哈希记录并【检验】是否有新加入的重复元素
2.滑动窗口
3.维护窗口,调整头指针【前进到重复元素的后一位】,更新结果【清空】【补充】
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int begin=0;//头指针
int result=0;
string word="";//加个空格就错了
int char_map[128]={0};//数组哈希
for(int i=0;i<s.length();i++){
char_map[s[i]]++;//用哈希数组记录各个字符的个数
if(char_map[s[i]]==1){
word+=s[i];
if(result<word.length()){
result=word.length();//更新最大长度
}
}
else{
while(begin<i&&char_map[s[i]]>1){//调整begin的位置,清除char_map中重复的字符
char_map[s[begin]]--;
begin++;
}
word="";
for(int j=begin;j<=i;j++){//从新的begin开始重新更新word,改变的不是begin,然后再进行i的for循环
word+=s[j];
}
}
}
return result;
}
};
作者:xia-mu-lao-zhang-ren
链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-33z96/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
五,重复的DNA序列
LeetCode 187. Repeated DNA Sequences
方法一:哈希map,枚举字符串中所有长度为10的子串,记录所有子串数量
有就加进去,没有就新加映射
class Solution {
public:
vector<string> findRepeatedDnaSequences(string s) {
map<string,int>word_map;//<单词,单词数量>映射
vector<string>result;
for(int i=0;i<s.length();i++){
string word=s.substr(i,10);
if(word_map.find(word)!=word_map.end()){//若在哈希表中出现
word_map[word]+=1;
}
else{
word_map[word]=1;//没有出现就添加进去
}
}
map<string,int>::iterator it;
for(it=word_map.begin();it!=word_map.end();it++){
if(it->second>1){
result.push_back(it->first);
}
}
return result;
}
};
作者:xia-mu-lao-zhang-ren
链接:https://leetcode-cn.com/problems/repeated-dna-sequences/solution/zhong-fu-de-dnaxu-lie-by-xia-mu-lao-zhan-vu4v/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
方法二:整数编码,【左移右移运算未掌握】【未解决】
六,最小窗口子串
LeetCode 76. Minimum Window Substring
1.滑动窗口 ,就是【看字符数量】,和顺序无关
2.字符哈希统计s,t字符数量
3.将t中出现的字符push到vec中
4.数组下标也可以是char
5.如何维护最小窗口,头指针移动的2个条件
class Solution {
private:
bool is_window_ok(int map_s[],int map_t[],vector<int>&vec_t){
for(int i=0;i<vec_t.size();i++){
if(map_s[vec_t[i]]<map_t[vec_t[i]]){
return false;//如果s出现的字符数量小于t中该字符的数量
}
}
return true;
}
public:
string minWindow(string s, string t) {
const int max_array_len=128;//char 0-127,用数组下标记录字符个数
int map_t[max_array_len]={0};
int map_s[max_array_len]={0};
vector<int>vec_t;//记录t字符串中有哪些字符
for(int i=0;i<t.length();i++){
map_t[t[i]]++;//遍历t,记录各个字符的个数
}
for(int i=0;i<max_array_len;i++){
if(map_t[i]>0){
vec_t.push_back(i);//遍历,将字符串t中出现的字符存储到vec_c中【为啥是i?】
}
}
int window_begin=0;
string result;
for(int i=0;i<s.length();i++){
map_s[s[i]]++;//遍历s,记录各个字符的个数
while(window_begin<i){//窗口头指针小于尾指针
char begin_ch=s[window_begin];//窗口头指针指向的字符
if(map_t[begin_ch]==0){//【数组里应该是整型,结果是char】//如果没有出现过
window_begin++;
}
else if(map_s[begin_ch]>map_t[begin_ch]){//出现了,数量足够,两个a
map_s[begin_ch]--;
window_begin++;
}
else{
break;
}
}
if(is_window_ok(map_s,map_t,vec_t)){
int new_window_len=i-window_begin+1;
if(result==""||result.length()>new_window_len){
result=s.substr(window_begin,new_window_len);//如果有更短的就更新result
}
}
}
return result;
}
};