• 【剑指Offer-字符串】面试题5:替换空格


    题目描述

    请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

    思路1

    如果不要求原地替换的话,设置一个新的字符串 ans,遍历输入的字符串 s,如果 s[i] 为空格,则 ans += "%20",否则的话 ans += s[i]。代码如下:

    class Solution {
    public:
        string replaceSpace(string s) {
            if(s.empty()) return s;
    
            string ans = "";
            for(int i=0; i<s.size(); i++){
                if(s[i]!=' ') ans += s[i];
                else ans += "%20";
            }
            return ans;
        }
    };
    

    思路2

    一种比较容易想到的方法就是从左到右遍历该字符串,当碰到空格的时候就把空格替换为%20,因为从1个字符(' ')替换为了3个字符('%20'),所以要对空格后面的字符进行移动。假设字符串长度为n,对于每个空格字符,需要移动后面的O(n)的字符,因此对于含有O(n)个空格字符的字符串而言,总的时间复杂度为(O(n^2))

    思路1对应的代码如下

    class Solution {
    public:
        // str为输入的字符串,length为总的可用长度
    	void replaceSpace(char *str,int length) {
            if(str==nullptr || length==0)
                return;
            
            int strLen = 0;    //字符串长度
            while(str[strLen]!='')
                strLen++;
            
            for(int i=0; i<strLen; i++){
                if(str[i]==' '){
                    for(int j=strLen; j>i; j--)
                        str[j+2] = str[j];    //注意是加2
                    str[i] = '%';
                    str[i+1] = '2';
                    str[i+2] = '0';
                    strLen += 2;
                }
            }
              
    	}
    };
    

    思路3

    思路1的时间复杂度太高了,思路1是从左到右扫描字符串然后移动,这就导致了一些字符被移动多次。可以换一个思路,从右到左扫描字符串。首先分配好替换后字符串的空间,如果原来的字符串为n,共s个空格字符,那么替换后的字符串长度为n+2*s。我们设置两个指针,一个指向替换前的字符串末尾p1,另一个指向替换后的字符串末尾p2。两个指针都从右向左移动,首先对当前p1指向的字符进行判断:若p1指向的字符c1不是空格,那么将c1复制到p2指向的位置,p2向左移动一位;如果p1指向的字符c1是空格,那么将p2以及p2的左两位填充为%20,p2向左移动2位。最后,将p1向左移动一位,重复此过程,直至p1将替换前的字符串从右到左遍历一遍。假设字符串长度为n,因为所有的字符只移动1次,所以时间复杂度为O(n)。

    思路2对应的代码如下

    class Solution {
    public:
    	void replaceSpace(char *str,int length) {
            if(str==nullptr || length==0)
                return;
            
            int strLen = 0;
            int bsCnt = 0;    //空格个数
            for(int i=0; str[i]!=''; i++){
                strLen++;
                if(str[i]==' ')
                    bsCnt++;
            }
            int newStrLen = strLen + 2*bsCnt;
            
            int cur1 = strLen;    //替换前的字符串长度
            int cur2 = newStrLen;    //替换后的字符串长度
            while(cur1>=0 && cur2>cur1){    //条件只写cur1>=0牛客网可以通过
                if(str[cur1]==' '){
                    str[cur2--] = '0';
                    str[cur2--] = '2';
                    str[cur2--] = '%';
                }
                else str[cur2--] = str[cur1];
                cur1--;
            }
              
    	}
    };
    

    如果输入是 string 的话,这样写

    class Solution {
    public:
        string replaceSpace(string s) {
            if(s.empty()) return s;
    
            int l1 = s.size();
            for(int i=0; i<l1; i++){
                if(s[i]==' ') s += "00"; // 注意是加两个零,不是3个
            }
            int l2 = s.size()-1;
    
            for(int i=l1-1; i>=0; i--){
                if(s[i]==' '){
                    s[l2--] = '0';
                    s[l2--] = '2';
                    s[l2--] = '%';
                }else s[l2--] = s[i];
            }
            return s;
        }
    };
    

    总结

    在合并两个字符串(或者数组时),如果从左到右复制每个字符(或数字),则需要重复移动字符(或数字)多次。这种情况下,可以考虑从右向左移动字符,这样能减少移动的次数,从而提高效率。

  • 相关阅读:
    删除 node_modules文件夹cmd指令
    vue 限制输入字符长度
    vertical-align和text-align属性实现垂直水平居中
    二分查找法
    MySQL实现分页查询
    数据库连接
    AOP编程的常用实现方式
    链表中环的入口
    AQS同步组件及ReentrantLock和synchronized的区别
    快速排序的递归和非递归
  • 原文地址:https://www.cnblogs.com/flix/p/12163471.html
Copyright © 2020-2023  润新知