【1++的刷题系列】之剑指offer(字符篇)

本文介绍了三种不同的方法来替换字符串中的空格,包括直接复制、插入删除和双指针法。接着,讨论了左旋转字符串的三种策略,包括两次反转和分段接收。此外,还详细解析了如何判断一个字符串是否表示数值,涉及符号、小数点和指数的检查。最后,提供了两种将字符串转换为整数的实现,考虑了正负号和溢出问题。
摘要由CSDN通过智能技术生成

👍作者主页:进击的1++
🤩 专栏链接:【1++的刷题系列】

一,替换空格

题目:请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

1.1 题解一

代码如下:

     string replaceSpace(string s)
    {
        string tmp;
        string::iterator it = s.begin();
        while (it != s.end())
        {
            if (*it == ' ')
            {
                tmp += "%20";

            }
            else
            {
                tmp += *it;
            }
            it++;

        }
        s = tmp;
        return s;
    }

这个方法主要利用的是用空间换时间,时间复杂度为O(n),空间复杂度为O(n)。用迭代器遍历字符串,用另一个新的对象进行接收,遇到空格就换为“%20”。若返回新的对象,则新对象得用static修饰为静态变量。

1.2 题解二

   string replaceSpace(string s)
    {
        int n = s.size();
        int i = 0;
        while (i < n)
        {
            if (s[i] == ' ')
            {
                s.insert(i, "%20");
                i += 2;
                cout << s << endl;
                s.erase(i + 1, 1);
                n += 2;
            }
            i++;
        }

        return s;

    }

利用string类的成员函数:插入,删除。进行操作。此方法由于插入删除时涉及元素的挪动。因此时间复杂度为O(n^2),空间复杂度为O(n)。

1.3 题解三

 string replaceSpace(string s)
    {
        //计算出空格
        int num_null = 0;
        int n = s.size();
        int i = 0;
        while (i < n)
        {
            if (s[i] == ' ')
            {
                num_null++;
            }
            i++;
        }

        //将空格替换成%20后的新的有效值大小(size)
        s.resize(n + num_null * 2);
        int old_n = s.size();
        int j = 0;
        //前后双指针法
        for (i = n - 1, j = old_n - 1; j > i; i--, j--)
        {
            if (s[i] != ' ')
            {
                s[j] = s[i];
            }
            else
            {
                s[j] = '0';
                s[j - 1] = '2';
                s[j - 2] = '%';
                j -= 2;
            }

        }
        return s;

    }

先计算出空格的数量,再增加对象中的有效字符即(size)的大小。利用前后双指针,将每个非空字符挪到将字符串中的空格全部替换后的对应位置,由于我们已经将“%20”所占的位置提前空出来了,所以,当遇到空格时只需将:“%20”放入即可。

二,左旋转字符串

题目:字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。

2.1 题解一

   string reverseLeftWords(string s, int n)
    {
        int sz = s.size();
        n = n % sz;
        int left = 0;
        int right = n - 1;
        while (left < right)
        {
            swap(s[left++], s[right--]);
        }

        left = n;
        right = sz - 1;
        while (left < right)
        {
            swap(s[left++], s[right--]);
        }

        left = 0;
        right = sz - 1;
        while (left < right)
        {
            swap(s[left++], s[right--]);
        }
        return s;
    }

拿字符串“abcde"举例,其左旋两位得”cdeab"。通过观察我们可以发现若将旋转的两位逆置,将不旋转部分逆置,再整体逆置就可以得到左旋两位后的结果。

2.2 题解二

   string reverseLeftWords(string s, int n)
    {
        string tmp;
        int sz = s.size();
        n = n % sz;
        int _n = n;
        while (n < sz)
        {
            tmp += s[n++];
        }
        int i = 0;
        while (i < _n)
        {
            tmp += s[i++];
        }
        return tmp;
    }

将字符串分为两部分:旋转部分与不旋转部分。计算出不旋转部分的下标,将其用另一个对象接收,直到此部分全部接受,再接收旋转部分的元素。

2.3 题解三

  string reverseLeftWords(string s, int n)
    {
        int sz = s.size();
        n = n % sz;
        string tmp;
        tmp.resize(sz);

        for (int i = 0; i < sz; i++)
        {
            tmp[(i + (sz - n)) % sz] = s[i];

        }
        return tmp;
    }

若将其看作 “圆” 左旋n相当于右旋length-n,再用另一个对象接收,并且下标模字符串长度,保证其仍在n内。

三,表示数值的字符串

题目:实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
数值(按顺序)可以分成以下几个部分:
若干空格
一个 小数 或者 整数
(可选)一个 ‘e’ 或 ‘E’ ,后面跟着一个 整数
若干空格

小数(按顺序)可以分成以下几个部分:
(可选)一个符号字符(‘+’ 或 ‘-’)
下述格式之一:
至少一位数字,后面跟着一个点 ‘.’
至少一位数字,后面跟着一个点 ‘.’ ,后面再跟着至少一位数字
一个点 ‘.’ ,后面跟着至少一位数字

整数(按顺序)可以分成以下几个部分:
(可选)一个符号字符(‘+’ 或 ‘-’)
至少一位数字

3.1 题解一

bool isNumber(string s) {
        int k = 0;
        while (s[k] == ' ')k++;
        if (!isnum(s, k, 1))return false;//判断前面的数是否合理
        if (s[k] == 'e' || s[k] == 'E') {
            k++;
            if (!isnum(s, k, 0))return false;//整数判断
        }
        while (s[k] == ' ')k++;
        return k == s.size();//若出现不满足条件的字符,k会卡在某个关节无法进行
    }
    bool isnum(string & s, int& k, int spot) {
        if (s[k] == '+' || s[k] == '-')k++;
        int first = k + spot;
        while ('0' <= s[k] && s[k] <= '9' || s[k] == '.') {
            if (s[k] == '.') {
                spot--;
                if (spot < 0)return false;
            }
            k++;
        }
        return first < k + spot;
    }

其主要思想为:组合一个正确的数值字符串。若最后未能够组成,则返回假。

3.2 题解二

bool isNumber(string s) {
        int i = 0, j = s.size() - 1;
        //找到字符串中第一个不为空的位置
        for (; i < s.size(); i++)
        {
            if (s[i] != ' ') break;
        }
        //从末尾找到字符串最后一个不为空的位置
        for (; j > 0; j--)
        {
            if (s[j] != ' ') break;
        }
        //判断是否为数值,以及是否有小数点和e/E
        bool num_flag = false;
        bool dot_flag = false;
        bool e_flag = false;
        for (int k = i; k < j + 1; k++)
        {
            //判断是否为数字
            if (isdigit(s[k]))
            {
                num_flag = true;
            }
            //判断是否为小数点,并且之前是否出现过小数点和e/E
            else if (s[k] == '.' && !dot_flag && !e_flag)
            {
                dot_flag = true;
            }
            //判断是否为e/E,并且之前是否出现过e/E和数字
            else if ((s[k] == 'e' || s[k] == 'E') && !e_flag && num_flag)
            {
                e_flag = true;
                //因为e/E的前后必须都是数字,所以如果找到了e/E就把num_flag设为false,
                //遇到下一个数字再设为true,避免出现12e的情况
                num_flag = false;
            }
            //判断是否为+-,并且符号是否在数值的首位,或者前一位是e/E
            else if ((s[k] == '+' || s[k] == '-') && (k == i || s[k - 1] == 'e' || s[k - 1] == 'E'))
            {
                continue;
            }
            //其他均为非法情况,输出false
            else return false;
        }
        return num_flag;
    }

四,把字符串转换成整数

题目:写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。

4.1 题解一

   long long conversion_num(string & s, int flag)
    {
        int n=s.size();
        int i=n-1;
        long long num=0;
        long long k=1;
        while(i>=0)
        {
            num=num+k*(s[i]-'0');
            k*=10;
            i--;
           
        }
        //cout<<num<<endl;
        return num;
        }
        //cout<<num<<endl;
        return num;

    }

    int strToInt(string str)
    {
        //跳过空格
        int i = 0;
        while (str[i] == ' ')
        {
            i++;
        }
        int flag = 1;//默认为正
        if (str[i] == '+' || str[i] == '-')
        {
            if (str[i] == '-')
            {
                flag = -1;
            }
            i++;
        }
        //跳过0
        while (str[i] == '0')
        {
            i++;
        }

        if (str[i] < '0' || str[i]>'9')
        {
            return 0;
        }

        string tmp;
        while (str[i] >= '0' && str[i] <= '9')
        {
            tmp += str[i];
            i++;
        }
        //cout<<tmp<<endl;
        if (tmp.size() > 10)
        {
            if (flag == -1)
                return INT_MIN;
            else
                return INT_MAX;
        }
        //字符转换为数字
        long long num = conversion_num(tmp, flag);
        //cout<<ret<<endl;
        //cout<<INT_MAX<<endl;

        num *= flag;
        if (num > INT_MAX)
        {
            return INT_MAX;
        }
        else if (num < INT_MIN)
        {
            //cout<<INT_MIN<<endl;
            return INT_MIN;
        }
        else
        {
            return num;
            //cout<<"sf"<<endl;
        }


    }

4.2 题解二

    int strToInt(string s) 
    {
         int i=0;
        int j=s.size()-1;
        //只有一个元素时得情况
        if(s.size()==1&&(s[i]==' '||s[i]=='+'||s[i]=='-'))
        return 0;
        //找出数值部分第一个值
        while(i<=j)
        {
            if(isdigit(s[i])||s[i]=='+'||s[i]=='-')
            break;
            else if(s[i]==' ')
            {
                i++;
                continue;
            }
            else
            return 0;
            i++;
        }
        //找出数值部分最后一个值
        while(j>=0)
        {
            if(isdigit(s[j]))
            break;
            j--;
        }
        //判断正负
        int flag=1;//默认为正
        if(s[i]=='-'||s[i]=='+')
        {
            if(s[i+1]=='+'||s[i+1]=='-')
            return 0;
            if(s[i]=='-')
            flag=-1;
            i++;
        }
        //判断是否超过int范围
        long long num=0;
        bool overflow=false;//默认未超出范围
        for(;i<=j;i++)
        {
            if(!isdigit(s[i]))
            break;
            num=num*10+s[i]-'0';
            if(num>(int)num)
            {
                overflow=true;
                break;
            }

        }
        //输出
        if(!overflow)
        {
            return flag*num;
        }
        else
        {
            if(flag==-1)
            return INT_MIN;
            else
            return INT_MAX;
        }


    }
   
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击的1++

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值