数据结构以学带练day8——反转字符串、替换空格、反转字符串中单词、左旋转字符串

59 阅读1分钟

题目

344. 反转字符串

image.png

双指针法

思路:一前一后双指针,swap函数交换

class Solution {
public:
    void reverseString(vector<char>& s) {
        int num = s.size();
        //定义一个头和尾指针往中间靠
        for(int i=0,j=num-1;i<j;i++,j--){
            swap(s[i],s[j]);
        }
    }
};

541. 反转字符串 II

image.png

reverse()函数方法

解法一:

  • for循环中的i每次加2k个
class Solution {
public:
    string reverseStr(string s, int k) {
        for (int i = 0; i < s.size(); i += (2 * k)) {
            // 1. 每隔 2k 个字符的前 k 个字符进行反转
            // 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
            if (i + k <= s.size()) {
                reverse(s.begin() + i, s.begin() + i + k );
            } else {
                // 3. 剩余字符少于 k 个,则将剩余字符全部反转。
                reverse(s.begin() + i, s.end());
            }
        }
        return s;
    }
};

解法二:

  • 用一个pos进行计数
class Solution {
public:
    string reverseStr(string s, int k) {
        int n = s.size(),pos = 0;
        while(pos < n){
            //剩余字符串大于等于k的情况
            if(pos + k < n) 
                reverse(s.begin() + pos, s.begin() + pos + k);
            //剩余字符串不足k的情况 
            else 
                reverse(s.begin() + pos,s.end());
            pos += 2 * k;
        }
        return s;
    }
};

剑指 Offer 05. 替换空格

自己的想法

  • 首先本题要注意的是'%20'属于三个字符,绝对不能s[i] = '%20',这样只会添加最后一个字符
  • 思路:新开一个字符串t,满足条件则依次添加'%','2','0'这三个字符,最后返回t。
class Solution {
public:
    string replaceSpace(string s) {
        string t;
        for(int i=0;i<s.size();i++){
            if(s[i] == ' '){
                t.push_back('%');
                t.push_back('2');
                t.push_back('0');
            }
            else{
                t.push_back(s[i]);
            }
        }
        return t;
    }
};
class Solution {
public:
    string replaceSpace(string s) {
        string t;
        for(int i=0;i<s.size();i++)
        {
            if(s[i]==' ')
            {
                t += "%20";
            }
            else
            {
                t += s[i];
            }
        }
        return t;
    }
};

replace()函数+迭代法

class Solution {
public:
    string replaceSpace(string s) {
        if(s.find(" ")!=-1) {
            //用str替换指定字符串从起始位置pos开始长度为len的字符:
            //string.replace(size_t pos, size_t len, const string& str);
            s.replace(s.find(" "), 1, "%20");
            s=replaceSpace(s);
        }
        return s;
    }
};

双指针法

替换空格.gif

class Solution {
public:
    string replaceSpace(string s) {
        int count = 0; // 统计空格的个数
        int sOldSize = s.size();
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == ' ') {
                count++;
            }
        }
        // 扩充字符串s的大小,也就是每个空格替换成"%20"之后的大小
        s.resize(s.size() + count * 2);
        int sNewSize = s.size();
        // 从后先前将空格替换为"%20"
        for (int i = sNewSize - 1, j = sOldSize - 1; j < i; i--, j--) {
            if (s[j] != ' ') {
                s[i] = s[j];
            } 
            else {
                s[i] = '0';
                s[i - 1] = '2';
                s[i - 2] = '%';
                i -= 2;
            }
        }
        return s;
    }
};

151. 反转字符串中的单词

image.png

双指针法

思路:

  1. 删除多余的空格
  2. 将整个字符串反转
  3. 按空格将每个单词反转

1. 删除多余空格

O(n)O(n)复杂度写法——双指针法
//去除所有空格并在相邻单词之间添加空格, 快慢指针。
void removeExtraSpaces(string& s) {
    int slow = 0;   
    for (int i = 0; i < s.size(); ++i) { 
        //遇到非空格就处理,即删除所有空格。
        if (s[i] != ' ') { 
            //手动控制空格,给单词之间添加空格。slow != 0说明不是第一个单词,需要在单词前添加空格。
            if (slow != 0) s[slow++] = ' '; 
            //补上该单词,遇到空格说明单词结束。
            while (i < s.size() && s[i] != ' ') { 
                s[slow++] = s[i++];
            }
        }
    }
    s.resize(slow); //slow的大小即为去除多余空格后的大小。
}
O(n2)O(n^2)复杂度写法——erase()函数法
  • erase()函数时间复杂度是O(n)O(n)
void removeExtraSpaces(string& s) {
    //删除中间多余空格
    for (int i = s.size() - 1; i > 0; i--) {
        //如果是多个空格相连,删了只剩一个
        if (s[i] == s[i - 1] && s[i] == ' ') {
            s.erase(s.begin() + i);
        }
    }
    // 删除字符串最后面的空格
    if (s.size() > 0 && s[s.size() - 1] == ' ') {
        s.erase(s.begin() + s.size() - 1);
    }
    // 删除字符串最前面的空格
    if (s.size() > 0 && s[0] == ' ') {
        s.erase(s.begin());
    }
}

2. 反转字符串

// 反转字符串s中左闭右闭的区间[start, end]
void reverse(string& s, int start, int end) {
    for (int i = start, j = end; i < j; i++, j--) {
        swap(s[i], s[j]);
    }
}

3.整体代码

class Solution {
public:
    void reverse(string& s, int start, int end){ //翻转,区间写法:左闭右闭 []
        for (int i = start, j = end; i < j; i++, j--) {
            swap(s[i], s[j]);
        }
    }

    void removeExtraSpaces(string& s) {
        int slow = 0;   
        for (int i = 0; i < s.size(); ++i) { 
            //遇到非空格就处理,即删除所有空格。
            if (s[i] != ' ') { 
               //手动控制空格,给单词之间添加空格。slow != 0说明不是第一个单词,需要在单词前添加空格。
                if (slow != 0) s[slow++] = ' '; 
                //补上该单词,遇到空格说明单词结束。
                while (i < s.size() && s[i] != ' ') { 
                    s[slow++] = s[i++];
                }
            }
        }
        s.resize(slow); //slow的大小即为去除多余空格后的大小。
    }

    string reverseWords(string s) {
        removeExtraSpaces(s); //去除多余空格,保证单词之间之只有一个空格,且字符串首尾没空格。
        reverse(s, 0, s.size() - 1);
        int start = 0; //removeExtraSpaces后保证第一个单词的开始下标一定是0。
        for (int i = 0; i <= s.size(); ++i) {
            if (i == s.size() || s[i] == ' ') { //到达空格或者串尾,说明一个单词结束。进行翻转。
                reverse(s, start, i - 1); //翻转,注意是左闭右闭 []的翻转。
                start = i + 1; //更新下一个单词的开始下标start
            }
        }
        return s;
    }
};

剑指 Offer 58 - II. 左旋转字符串

image.png

自己想法——暴力解法

class Solution {
public:
    string reverseLeftWords(string s, int n) {
        string pre;//用于记录
        string result;//最终结果字符串
        //遍历s中前n个字符,存入pre
        for(int i=0;i<n;i++){
            pre+=s[i];
        }
        //遍历s,取后面的字符,存入result
        for(int i=0;i<s.size();i++){
            if(i>=n){
                result+=s[i];
            }
        }
        //遍历pre,取pre字符存入result
        for(int i=0;i<pre.size();i++){
            result+=pre[i];
        }
        return result;
    }
};

进阶:不能申请额外空间,只能在本串上操作——空间复杂度O(1)O(1)

思路:(随便带个例子就能知道这思路没问题)

  1. 反转区间为前n的子串
  2. 反转区间为n到末尾的子串
  3. 反转整个字符串
class Solution {
public:
    string reverseLeftWords(string s, int n) {
        //反转区间为前n的子串
        reverse(s.begin(),s.begin()+n);
        //反转区间为n到末尾的子串
        reverse(s.begin()+n,s.end());
        //反转整个字符串
        reverse(s.begin(),s.end());
        return s;
    }
};

字符切分与拼接法

substr(0,n):C++中的字符切分函数。

image.png

class Solution {
public:
    string reverseLeftWords(string str,int n){
        if(str.size()==0) return str;
        string s = str.substr(0,n);
        string res = str.substr(n,str.size()-n) + s;
        return res;
    }
};

总结

今日学习时长:3h+30min