哈希表和字符串—205. 同构字符串 1002. 查找共用字符 925. 长按键入 844.比较含退格的字符串 C++实现

205. 同构字符串

在这里插入图片描述

class Solution {
public:
    bool isIsomorphic(string s, string t) {
        unordered_map<char, char> map1;
        unordered_map<char, char> map2;
        for(int i=0, j=0; i<s.size(); i++, j++)
        {
            // map1保存s[i] 到 t[j]的映射
            if(map1.find(s[i]) == map1.end()) map1[s[i]] = t[j];
            // map2保存t[j] 到 s[i]的映射
            if(map2.find(t[j]) == map2.end()) map2[t[j]] = s[i];
            //比较
            if(map1[s[i]] != t[j] || map2[t[j]] != s[i]) return false;
        }
        return true;
    }
};

1002. 查找共用字符

在这里插入图片描述
统计出搜索字符串里26个字符的出现的频率,然后取每个字符频率最小值,最后转成输出格式

void *memset(void *s, int ch, size_t n);

函数解释:将s中当前位置后面的n个字节(typedef unsigned int size_t)用 ch 替换并返回s。
memset的作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法,也就是将已开辟内存空间 s 的首 n 个字节的值设为值(非数值型字符) c。

class Solution {
public:
    vector<string> commonChars(vector<string>& words) {
        vector<string> result;//保存输出结果
        int hash[26] = {0};//统计所有字符的频率
        //1.剔除
        if(words.size() == 0) return result;
        //2.用words的第一个字符初始化hash
        for(int j=0; j<words[0].size(); j++)
        {
            hash[words[0][j] - 'a']++;
        }
        //for(int word : words[0]) hash[word - 'a']++;

        //3.统计words其他字符串的频率 并更新hash
        int hash1[26] = {0};//统计words中除第一个字符串的频率
        for(int i=1; i<words.size(); i++)
        {
            //清零hash1 0填充hash1 大小是26*sizeof(int)
            memset(hash1, 0, 26*sizeof(int));
            for(int j = 0; j <words[i].size(); j++)
            {
                //统计words其他字符串的频率
                hash1[words[i][j] - 'a']++;
            }
            
            //用hash1更新hash中的最小频率 遍历26个字母
            for(int i=0; i<26; i++)
            {
                hash[i] = min(hash[i], hash1[i]);
            }
        }
        //4.转化输出结果 遍历26个字母
        for(int i=0; i<26; i++)
        {
            //题目中包括重复字符
            while(hash[i] != 0)
            {
                string temp(1, i + 'a');//char转string
                result.push_back(temp);
                hash[i]--;//保存一次字符 频率减少一次
            }
        }
        return result;
    }
};

925. 长按键入

在这里插入图片描述
双指针,同时遍历name和type, 时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( 1 ) O(1) O(1),有三种情况

  1. name和type都遍历完了
  • name[i]和type[j]相同,i和j继续移动
  • name[i]和type[j]不相同
    • 如果type[j]的第一个字符就不同,即j=0时就不相同,false
    • 如果type[j]的第一个字符相同,j继续移动,跳过重复项。再次比较name[i]和type[j],如果相同,i和j继续移动;如果不相同,false
  1. name没有遍历完,false
  2. type没有遍历完,遍历剩余项,比较type[j]和type[j-1]
class Solution {
public:
    bool isLongPressedName(string name, string typed) {
        int i=0, j=0;
        while(i<name.size() && j<typed.size())
        {
            if(name[i] == typed[j])
            {
                i++;
                j++;
            }
            else
            {
                if(j == 0) return false;//如果第一位就不相同 返回false
                // j跨越重复项,向后移动,同时防止j越界
                while(j<typed.size() && typed[j] == typed[j-1]) j++;
                //跨越重复项后继续比较
                if(name[i] == typed[j])
                {
                    i++;
                    j++;
                }
                else return false;
            }
        }
        //name没有匹配完
        if(i < name.size()) return false;
        //type没有匹配完
        while(j < typed.size())
        {
            if(typed[j] == typed[j-1]) j++;
            else return false;
        }
        return true;
    }
};

844.比较含退格的字符串

在这里插入图片描述

栈模拟

  • 空间复杂度 O ( n + m ) O(n+m) O(n+m),时间复杂度 O ( n + m ) O(n+m) O(n+m)
  • 如果不是#字符,累加字符;如果是#字符且栈非空,弹出栈顶字符。最后比较两个栈是否一样

写法1

class Solution {
public:
    bool backspaceCompare(string s, string t) {
        //方法1 栈模拟
        string ss;//当成栈
        string st;//当成栈
        for(int i=0; i<s.size(); i++)
        {
            if(s[i] != '#') ss += s[i];
            else if(!ss.empty()) ss.pop_back();
        }

        for(int i=0; i<t.size(); i++)
        {
            if(t[i] != '#') st += t[i];
            else if(!st.empty()) st.pop_back();
        }

        if(ss == st) return true;
        return false;
    }
};

写法2

class Solution {
public:
    bool backspaceCompare(string s, string t) {
        //方法1 栈模拟 写法2
        string ss = stackStr(s, '#');//当成栈
        string st = stackStr(t, '#');//当成栈
        if(ss == st) return true;
        return false;
    }
private:
    string stackStr(string& s, char c)
    {
        string ss;
        for(int i=0; i<s.size(); i++)
        {
            if(s[i] != c) ss += s[i];
            else if(!ss.empty()) ss.pop_back();
        }
        return ss;
    }
};

双指针

  • 空间复杂度 O ( 1 ) O(1) O(1),时间复杂度 O ( n + m ) O(n+m) O(n+m)
  • 双指针同时从后向前遍历S和T,记录#的数量,模拟消除的操作,就是#的数量减1。
  • 如果#用完了,比较S[i]和T[j],如果S[i]和T[j]不相同返回false。如果S或者T其中一个遍历完了,也返回false。
  • 最后如果S和T同时遍历完了,返回true,否则false。
class Solution {
public:
    bool backspaceCompare(string s, string t) {
        //方法2 双指针模拟
        int sSkipNum = 0;//记录s中#数量
        int tSikpNum = 0;//记录t中#数量
        int i = s.size()-1;
        int j = t.size()-1;
        while(1)
        {
            //处理s中#字符
            while(i >= 0)
            {
                //模拟s中#退回操作
                if(s[i] == '#') sSkipNum++;//记录#数量
                else
                {
                    if(sSkipNum > 0) sSkipNum--;//相当于用了一次# 模拟退回操作
                    else break;//文本为空 跳出循环
                }
                i--;
            }

            while(j >= 0)
            {
                //模拟t中#退回操作
                if(t[j] == '#') tSikpNum++;
                else
                {
                    if(tSikpNum > 0) tSikpNum--;
                    else break;
                }
                j--;
            }

            //s和t有一个遍历完了跳出循环
            if(i < 0 || j < 0) break;
            //比较s和t剩余字符
            if(s[i] != t[j]) return false;
            i--;
            j--;
        }
        //说明S和T同时遍历完毕
        if(i == -1 && j == -1) return true;
        else return false;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值