算法学习打卡day7 | 344.反转字符串、 541. 反转字符串II、 剑指Offer 05.替换空格、 151.翻转字符串里的单词、 剑指Offer58-II.左旋转字符串

344.反转字符串

力扣题目链接
题目描述:
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

示例 1:

输入:s = [“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]
思路:

  • 采用双指针法,left指向数组首元素,right指向最后一个元素,left位置元素和right互换,知道left等于right时退出

代码实现:

void reverseString(vector<char>& s) {
    for (int i = 0, j = s.size() - 1; i < s.size()/2; i++, j--) {
        swap(s[i],s[j]);
    }
}

541. 反转字符串II

力扣题目链接
题目描述:
给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

示例 1:

输入:s = “abcdefg”, k = 2
输出:“bacdfeg”
示例 2:

输入:s = “abcd”, k = 2
输出:“bacd”

思路:

  • 和普通字符串翻转类似,只不过需要通过控制循环得到 每隔 2k 个字符的前 k 个字符等子串,然后双指针法翻转子串即可。

代码实现

string reverseStr(string s, int k) {
        for (int i = 0; i < s.size(); i += (2 * k)) {
            // 1. 每隔 2k 个字符的前 k 个字符进行反转
            if (i + 2 * k <= s.size()) {
				 reverse(s.begin() + i, s.begin() + i + 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;
    }

合并改进后:

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;
    }

剑指Offer 05.替换空格

力扣题目链接
题目描述:
假定一段路径记作字符串 path,其中以 “.” 作为分隔符。现需将路径加密,加密方法为将 path 中的分隔符替换为空格 " ",请返回加密后的字符串。(原题是替换空格为%12,做法一样,但是需要自己增加数组的长度
示例 1:

输入:path = “a.aef.qerf.bb”

输出:“a aef qerf bb”

思路:

  • 循环遍历查找“.”然后替换成空格即可,如果是替换的元素比之前的字符长度大或者小,需要自行改变数组的长度

代码实现

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.翻转字符串里的单词

力扣题目链接
题目描述:
给你一个字符串 s ,请你反转字符串中 单词 的顺序。单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

示例 1:

输入:s = “the sky is blue”
输出:“blue is sky the”

思路:

  • 首选需要先去除字符串中多余的空格,然后对字符串进行整体反转,再部分反转,当然也可以部分反转然后整体反转
  • 难点:多余空格的去除(和移除元素类似,可以采用双指针法)//补充其他方法

代码实现

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;   //整体思想参考https://programmercarl.com/0027.移除元素.html
        for (int i = 0; i < s.size(); ++i) { //
            if (s[i] != ' ') { //遇到非空格就处理,即删除所有空格。
                if (slow != 0) s[slow++] = ' '; //手动控制空格,给单词之间添加空格。slow != 0说明不是第一个单词,需要在单词前添加空格。
                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;
    }

剑指Offer58-II.左旋转字符串

力扣题目链接
题目描述:
某公司门禁密码使用动态口令技术。初始密码为字符串 password,密码更新均遵循以下步骤:
设定一个正整数目标值 target,将 password 前 target 个字符按原顺序移动至字符串末尾
请返回更新后的密码字符串。

示例 1:

输入: password = “s3cur1tyC0d3”, target = 4
输出: “r1tyC0d3s3cu”
思路:

  • 和上题类似,但是不需要去除空格,直接通过区间定义先部分反转子字符串,然后整体反转字符串即可得到答案。
  • 如图:
    算法学习打卡day7 | 344.反转字符串、 541. 反转字符串II、 剑指Offer 05.替换空格、 151.翻转字符串里的单词、 剑指Offer58-II.左旋转字符串_第1张图片

代码实现

string reverseLeftWords(string s, int n) {
        reverse(s.begin(), s.begin() + n);
        reverse(s.begin() + n, s.end());
        reverse(s.begin(), s.end());
        return s;
    }

收获:

  • 学习了各种反转字符串,普通的双指针法反转,k个元素一组的字符串反转,单词反转(先整体反转再部分反转),单词左旋(先部分反转再整体反转)

你可能感兴趣的:(算法学习打卡,算法,学习,leetcode)