算法题之哈希表系列

题目一:赎金信
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false 。

magazine 中的每个字符只能在 ransomNote 中使用一次。
注意:
1 <= ransomNote.length, magazine.length <= 105
ransomNote 和 magazine 由小写英文字母组成
示例 1:

输入:ransomNote = “a”, magazine = “b”
输出:false
leetcode链接

由题目可知两个字符串中的字母都仅由小写字母构成,那么我们可以利用哈希表来存储magazine中每个字母的出现次数,然后再遍历ransomNote中的每个字母,如果该字母在map中未出现,那么直接返回false,如果出现,那么将出现的次数减1,如果值小于0那么也返回false,即为ranssomNote中每个字母如果在magazine中未出现或者是出现的次数大于magezine中出现的次数,就返回false

bool canConstruct(string ransomNote, string magazine) {
        unordered_map<char,int> map;
        //计算magazine中每个字母出现的次数
        for(int i=0;i<magazine.size();i++){
            map.count(magazine[i])==0?map[magazine[i]]=1:map[magazine[i]]++;
        }
        //计算ransomNote中每个字母出现的次数
        for(int i=0;i<ransomNote.size();i++){
            if(map.count(ransomNote[i])==0||--map[ransomNote[i]]<0){
                //如果在magazine中没有出现过该字母或者出现的次数大于magazine中的次数返回false
                return false;
            }
        }
        return true;
    }

题目二:单词规律
给定一种规律 pattern 和一个字符串 s ,判断 s 是否遵循相同的规律。

这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向连接的对应规律。

示例1:

输入: pattern = “abba”, s = “dog cat cat dog”
输出: true

leetcode链接

方法一:双哈希表
由题目可知,pattern中的字母和s中 的单词是一一对应的,即pattern中的字母只能对应与s中的一个单词,反过来,s中的单词也只能对应pattern中的一个字母,对于映射关系,我们很快能够想到利用hashmap,但是hashmap中关键字虽然是唯一的,但是关键字的值不是唯一的,也就是说可以有很多个关键字对应于同一个值,因此不满足我们题目所说双向对应,所以我们如果只用一个hashmap存储映射关系时,我们会错误的把值相同的映射关系也当成一种新的映射关系进行存储,那么我们如何避免这种情况呢,我们可以定义2个hashmap,一个保证pattern中的字母唯一,一个保证s中的单词唯一,这样只有保证了二者都唯一的映射关系,那么对于pattern和s都未出现过时我们才能够将他存储为新的映射关系,若二者其中之一出现过,我们再去这两个hashmap中查询是否满足原来的对应关系。
> 注:当然也可以只定义一个hashmap,然后去查找值有没有出现过,但是这样会增加时间复杂度hashmap查找value需要遍历整个hashmap
时间复杂度;o(n)
空间复杂度:o(n)

bool wordPattern(string pattern, string s) {
    unordered_map<string,char> map1;
    unordered_map<char,string> map2;
    int n = s.size();
    int m = pattern.size();
    int i = 0,j = 0;
    for(i=0;i<m&&j<n;i++,j++){
        string str = "";
        while(j<n&&s[j]!=' '){
            str+=s[j++];
        }
        if(map1.count(str)==0&&map2.count(pattern[i])==0){//该双向映射对不存在时,存储该双向映射对
            map1[str] = pattern[i];
            map2[pattern[i]] = str;
        }else if(map1[str]!=pattern[i]||map2[pattern[i]]!=str){//检查双向映射是否符合之前的映射规则
            return false;
        }
    }
    return j<n||i<m?false:true;//如果pattern中字母和s中单词的数量不匹配,那么直接返回false
}

题目三:有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。

示例 1:

输入: s = “anagram”, t = “nagaram”
输出: true
leetcode链接

方法一:排序
利用sort对两个字符串排序后,判断排序后的字符串是否相等
时间复杂度:o(logn) 快速排序的时间复杂度和空间复杂度为o(logn)
空间复杂度:o(logn)

bool isAnagram(string s, string t) {
    if(s.size()!=t.size()){
        return false;
    }
    sort(s.begin(),s.end());
    sort(s.begin(),s.end());
    return s==t;
}

方法二:利用额外空间
我们可以利用额外空间来存储每一个单词的出现次数,用vector和哈希表都可以,这里使用哈希表,先判断两个字符串的长度是否相等,不相等直接返回false,否则不想等我们把s中单词出现的次数存储下来,然后遍历字符串t,对于每一个字符,我们都讲其对应哈希表中出现的次数减1,如果发现不在哈希表中,或者是减1后的次数小于0(长度相等的字符串如果不相等肯定存在出现次数较大的字母),那么返回false。
时间复杂度:o(n)
空间复杂度:o(1)

bool isAnagram(string s, string t) {
    int n = s.size();
    int m = t.size();
    if(n!=m){
        return false;
    }
    unordered_map<char,int> map;
    for(int i=0;i<n;i++){
        map.count(s[i])==0?map[s[i]]=1:map[s[i]]++;
    }
    for(int i=0;i<m;i++){
        if(map.count(t[i])==0||--map[t[i]]<0){
            return false;
        }
    }
    return true;
}

你可能感兴趣的:(算法)