剑指offer C++ 字符串

9 篇文章 0 订阅

1.替换空格

解法1:STL

有已有的函数还是很舒服的,没什么好说的

class Solution {
public:
    string replaceSpace(string s) {
        for(int i=0;i<s.size();i++)
        {
            if(s[i]==' ') //有时候用惯了python,注意这里只能用单引号,C++里不一样的
            {
                s.replace(i,1, "%20");//这句话的意思从i位置开始的第一个字符进行替换
            }
        }
        return s;
    }
};

解法2:正常写法

创建一个新的数组
用这个新的函数遍历s字符串,如果遇到空格就添加3个新字符(%20)
把这个数组变成字符串

class Solution {
public:
    string replaceSpace(string s) {
        string s1(3*s.size(),0);//别忘了设置新字符串的大小
        int j=0;
        for(int i=0;i<s.size();i++)
        {
            if(s[i]!=' ')
            {
                s1[j++]=s[i];
            }
            else{//最好一个个写进去
                s1[j++]='%';
                s1[j++]='2';
                s1[j++]='0';
            }
        }
        return s1;
    }
};

其实也可以

 for(int i=0;i<s.size();i++)
        {
            if(s[i]==' '){
                a+="%20";
            }else{
                a+=s[i];
            }
        }

用 += 的话会频繁进行字符数组空间开辟和拷贝,每次都会产生一个新的String对象。s1(3*s.size(),0)直接给他分配一个需要的内存,虽然可能会占用多点内存,还是这样好点

解法3:python偷懒

s.replace(" ", "%20")//haha,这是不是作弊

2.第一个只出现一次的字符

解法1:哈希法

小tip:
for(char &c:str ), ### 法 1
for(char c:str ) ###法2
中遍历都可以,但法2会复制一个s字符串再进行遍历操作,法1直接引用原字符串进行遍历操作.法1用起来会更优,在内存or时间上

class Solution {
public:
    int FirstNotRepeatingChar(string str) {
        unordered_map<char, int> mp;//建立哈希
        for(char &c:str )//先遍历一边所有字符,并统计出现次数
            mp[c]++;
        for(int i=0;i<str.size();i++)//因返回的是位置,所以要用i遍历
        {
            if(mp[str[i]]==1)
                return i;
        }
        return -1;
    }
};

3.左旋转字符串

解法1:暴力破解

2个循环分别遍历从n开始和0-n部分

class Solution {
public:
    string LeftRotateString(string str, int n) {
        if (n > str.size()) return str;
        string string2="" ;
        for(int i=0;i<(str.size()-n);i++){//从n开始的部分
            string2[i] = str[i+n];
        }
        for(int i=0;i<n;i++)//n之前的部分
            string2[str.size()-n+i] = str[i];
        return string2;
    }
};

解法2:采用标准库

形式 : s.substr(pos, len)
返回值: string,包含s中从pos开始的len个字符的拷贝(pos的默认值是0,len的默认值是s.size() - pos)

class Solution {
public:
    string LeftRotateString(string str, int n) {
        if(str.empty()) return str;
        string string2;
        int j = str.size();
        n=n%j;  //应对移位大于字符串长度这种情况
        string2 = str.substr(n)+str.substr(0,n);
        return string2;
    }
};

4. 字符流中第一个不重复的字符

解法一:哈希法

感觉和上面第二题有点像,就是在哈希的基础上又加了一个创建了一个字符串。因为是字符流,不能确定字符串大小。只能来一个放进去一个。剩下的和第二题思路一样

class Solution
{
public:
  //Insert one char from stringstream
    string str;
    unordered_map<char, int> mp;
    void Insert(char ch) {
        str+=ch;//向字符串中插入字符流
        ++mp[ch];//统计出现次数
    }
  //return the first appearence once char in current stringstream
    char FirstAppearingOnce() {
        for(int i=0;i<str.size();i++)//遍历
        {
            if(mp[str[i]]==1)
                return str[i];
        }
       return '#';
    }
};

解法二:哈希+队列

来自https://blog.nowcoder.net/n/23f5c7b86af64c62b811c2e9ec2cf5b1?f=comment
感觉就是把字符串数组变成了队列

class Solution
{
public:
  //Insert one char from stringstream
    queue<char> q;
    unordered_map<char, int> mp;
    void Insert(char ch)
    {
         // 如果是第一次出现, 则添加到队列中
         if (mp.find(ch) == mp.end()) {
             q.push(ch);
         }
         // 不管是不是第一次出现,都进行计数
         ++mp[ch];
    }
  //return the first appearence once char in current stringstream
    char FirstAppearingOnce()
    {
        while (!q.empty()) {
            char ch = q.front();
            // 拿出头部,如果是第一次出现,则返回
            if (mp[ch] == 1) {
                return ch;
            }
            // 不是第一次出现,则弹出,然后继续判断下一个头部
            else {
                q.pop();
            }
        }
        return '#';
    }
};

5. 字符串的排列

解法一:递归法

递归的话就很简单了,以{1,2,3}为例,它的排列是:

以1开头,后面接着{2,3}的全排列,
以2开头,后面接着{1,3}的全排列,
以3开头,后面接着{1,2}的全排列.

class Solution {
public:
    vector<string> Permutation(string str) {
        if(str.empty()) return{};
        set<string> ret;//set可以进行去重,且可以按字母顺序排序
        perm(0,str,ret);
        return vector<string>({ret.begin(),ret.end()});
    }
    void perm(int index,string str,set<string> &ret)
    {
        if(index==str.length())//完成了一次全排列
        {
            ret.insert(str);
            return;
        }
        for(int i=index;i<str.size();i++)
        {
            swap(str[index],str[i]);
            perm(index+1,str, ret);// 回溯:比如第二次交换后是"BAC",需要回溯到"ABC"
            swap(str[index],str[i]);
        }
    }
};

解法二:字典法

这里比较偷懒用了
next_permutation:对于当前的排列,如果在字典序中还存在下一个排列,返回真,并且将下一个排列赋予当前排列,如果不存在,就把当前排列进行递增排序。

class Solution {
public:
     
    
    vector<string> Permutation(string str) {
        vector<string>ans;
        if(str.size()==0)return ans;
        sort(str.begin(),str.end());//将str里的按字典序排序
        do{
            ans.push_back(str);
        }while(next_permutation(str.begin(),str.end()));
        return ans;
    }
};

6.把字符串转换成整数

解法1:随便什么方法

注释应该写的清除了。核心很简单,就是要注意各种范围的界定。

class Solution {
public:
    int StrToInt(string str) {
        int num=0,a;
        if(str.size()<=0) return 0;//防止其为空
        if(str[0]=='-') //有-号情况
        {
             a=-1;
             str.erase(0,1);
            }
        else if(str[0]=='+') //有+号情况
        {
             a=1;
             str.erase(0,1);
        }
        else a=1;//没有号情况
        for(int j=0;j<str.size();j++)
        {
            if(!(str[j]>='0' && str[j]<='9'))//排除含有字母情形
                return 0;
            num = num*10+str[j]-'0';//核心语句
        }
        return num*a;
    }
};

7.正则表达式匹配

解法一:动态规划

参考链接:https://blog.csdn.net/gatieme/article/details/51542072?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162851058416780255294343%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162851058416780255294343&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v29-2-51542072.pc_search_download_positive&utm_term=%E7%89%9B%E5%AE%A2%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8C%B9%E9%85%8DC%2B%2B&spm=1018.2226.3001.4187

class Solution
{
public:
    bool match(string s, string p) {
        int m = s.size(), n = p.size();
        vector<vector<bool>> f(m + 1, vector<bool>(n + 1, false));

        f[0][0] = true;
        for (int i = 1; i <= m; i++)
            f[i][0] = false;
        // p[0.., j - 3, j - 2, j - 1] matches empty iff p[j - 1] is '*' and p[0..j - 3] matches empty
        for (int j = 1; j <= n; j++)
            f[0][j] = j > 1 && '*' == p[j - 1] && f[0][j - 2];

        for (int i = 1; i <= m; i++)
            for (int j = 1; j <= n; j++)
                if (p[j - 1] != '*')
                    f[i][j] = f[i - 1][j - 1] && (s[i - 1] == p[j - 1] || '.' == p[j - 1]);
                else
                    // p[0] cannot be '*' so no need to check "j > 1" here
                    f[i][j] = f[i][j - 2] || (s[i - 1] == p[j - 2] || '.' == p[j - 2]) && f[i - 1][j];

        return f[m][n];
    }
};
class Solution {
public:
    bool isMatch(string s, string p) {
        int m = s.size();
        int n = p.size();

        auto matches = [&](int i, int j) {
            if (i == 0) {
                return false;
            }
            if (p[j - 1] == '.') {
                return true;
            }
            return s[i - 1] == p[j - 1];
        };

        vector<vector<int>> f(m + 1, vector<int>(n + 1));
        f[0][0] = true;
        for (int i = 0; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (p[j - 1] == '*') {
                    f[i][j] |= f[i][j - 2];
                    if (matches(i, j - 1)) {
                        f[i][j] |= f[i - 1][j];
                    }
                }
                else {
                    if (matches(i, j)) {
                        f[i][j] |= f[i - 1][j - 1];
                    }
                }
            }
        }
        return f[m][n];
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/regular-expression-matching/solution/zheng-ze-biao-da-shi-pi-pei-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

8.表示数值的字符

解法一:一般解法

class Solution {
public:

    bool isNumeric(string str) {
        while(str.size()>0&&str[0]==' ') str.erase(0,1);//删除空格
        while(str.size()>0&&str[str.size()-1]==' ') str.erase(str.size()-1,1);
        bool a=false;
        bool b=false;
        bool c=false;
        for(int i=0;i<str.size();i++)
        {
            if(str[i]=='e'||str[i]=='E')//判断eE
            {
                if(b||!a){return false;}
                else{a=false;b=true;}
            }
            else if(str[i]=='.')//判断.
            {
                if(b||c) return false;
                c=true;
            }
            else if(str[i]>='0'&&str[i]<='9')//判断是否出现数字
            {
                a=true;
            }
            else if(str[i]=='+'||str[i]=='-')//判断正负号
            {
                if(i!=0&&(str[i-1]!='e'&&str[i-1]!='E')) return false;
            }
            else return false;
        }
        return a;
    }
};

解法二:正则表达式

#include <regex>
class Solution {
public:
    bool isNumeric(string str) {
        regex reg("([+-])?([0-9]*)?([0-9]+|\\d+\\.\\d*|\\.\\d+)(([eE])[+-]?\\d+)?$");
        //regex reg("[+-]?([0-9]+\\.?[0-9]*|[0-9]*\\.?[0-9]+)([eE][+-]?[0-9]+)?");
        return regex_match(str,reg);
    }
};

不知道为什么39个案例总是只能通过34个左右

java

class Solution {
    public boolean isNumber(String s) {
        if(s == null || s.length() == 0){
            return false;
        }

        //面向测试用例编程,末尾有空格算数字?不解
        s = s.trim();
        try{
            double a = Double.parseDouble(s);
        }catch (Exception e){
            return false;
        }

        char c = s.charAt(s.length()-1);
        //特,末尾有f,d,D这些不算,但是3.算数字(面向测试用例编程)
        return (c >= '0' && c <= '9') || c == '.';
    }
}

9.翻转单词序列

解法一:类似于栈

来源:https://www.nowcoder.com/profile/899694

根据空格获得单词的字符串,不断从前面插入反转后的语句中。从后往前遍历

class Solution {
public:
    string ReverseSentence(string str) {
        string tmp="";//单词
        string sent="";//反转后语句
        for(int i=0;i<str.size();i++)
        {
            if(str[i]==' ') sent = " "+tmp+sent,tmp="";
            else tmp = tmp+str[i];
        }
        if(tmp.size()) sent = tmp+sent;
        return sent;
        }
};

sent = " “+tmp+sent,tmp=”"这句不知道想表达什么意思

解法二:常规做法

常规,建立一个反转函数
先把整个字符串翻转,再对字符串中每个单词翻转,单词翻转2次再此变成正常顺序

class Solution {
public:
    void Reverse(string &str,int ben,int end)//翻转
    {
        while(ben<end)
            swap(str[ben++],str[end--]);
    }
    string ReverseSentence(string str) {
        int i=0,end=0,ben=0;//一定要初始化
        Reverse(str,0, str.size()-1);//把str整个字符串都翻转
        while(i<str.size())
        {
            while(i<str.size()&&str[i]==' ') i++;
            end=ben=i;//每个单词第一个字位置
            while(i<str.size()&&str[i]!=' ')
            {
                end++;i++;
            }
            Reverse(str, ben,end-1);//在单词内部翻转,变成原来正常的单词
        }
        return str;
    }
};

注意void Reverse(string &str,int ben,int end)这里字符串是取地址符,否则会出错

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值