Leetcode 344.反转字符串
思路分析:
反转字符串直观思路是对称交换两端的字符,即双指针法。
代码实现:
class Solution {
public:
void reverseString(vector<char>& s) {
int i=0, j=s.size()-1;
while (i <= j) {
swap(s[i],s[j]);
i++;
j--;
}
}
};
Leetcode 541. 反转字符串II
思路分析:
题意说了三种情况,可以拆解为反转前面第k个元素,和少于k的所有元素全部反转。可用for循环,2*k的间隔更新一次,如果i+k小于s.size(),则反转i到i+k区间的元素,可使用std::reverse库函数。如果i+k超过了s.size(),则反转i到末尾的所有元素。因为是对s本身的修改,所以操作完后,直接返回s就好。
代码实现:
class Solution {
public:
string reverseStr(string s, int k) {
for (int i = 0; i < s.size(); i += (2 * k)) {
if (i + k <= s.size()) {
reverse(s.begin() + i, s.begin() + i + k );
} else {
reverse(s.begin() + i, s.end());
}
}
return s;
}
};
Leetcode 剑指Offer 05.替换空格
思路分析:
直观解法如方法1,直接申请个辅助空间,遍历原字符串,遇到空格,就替换成"%20"。但该方法空间复杂度不如方法2.
方法2使用双指针从后往前遍历,一个指针指向新字符串的末尾,另一个指向旧字符串的末尾。【《代码随想录》的解法】,该方法时间复杂度为o(n), 空间复杂度为O(1)。
代码实现:
方法1:申请辅助空间
class Solution {
public:
string replaceSpace(string s) {
if (s.empty()) {
return "";
}
string s_copy;
int space_num = 0;
int origin_length = 0;
for (auto ch:s) {
if (ch == ' ') {
space_num++;
s_copy.push_back('%');
s_copy.push_back('2');
s_copy.push_back('0');
} else {
s_copy.push_back(ch);
}
origin_length++;
}
return s_copy;
}
};
方法2:不申请辅助空间,双指针法,从后向前操作
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;
}
};
Leetcode 151.翻转字符串里的单词
思路分析:
本题的思路是先移除前导空格、尾随空格或者单词间多出的空格,再对整个字符串进行反转,最后把每个单词反转,即得到最终结果。reverse的逻辑和反转字符串,反转字符串II一样。本题难点是使用时间复杂度为o(n),空间复杂度为o(1)的算法实现移除多余的空格。
当然有些语言有split和join库函数,如python实现非常简洁,只是失去本题考察的意义。
代码实现:
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] != ' ') {
if (slow != 0) s[slow++] = ' ';
while (i < s.size() && s[i] != ' ') {
s[slow++] = s[i++];
}
}
}
s.resize(slow);
}
string reverseWords(string s) {
removeExtraSpaces(s);
reverse(s, 0, s.size() - 1);
int start = 0;
for (int i = 0; i <= s.size(); ++i) {
if (i == s.size() || s[i] == ' ') {
reverse(s, start, i - 1);
start = i + 1;
}
}
return s;
}
};
使用spilt和join:
class Solution:
def reverseWords(self, s: str) -> str:
return " ".join(reversed(s.split()))
Leetcode 剑指Offer58-II.左旋转字符串
思路分析:
直观的思路是分别保存n前后的子字符串,然后把前面子字符串的字符放到后面子字符串后面。见方法1。
不用申请额外的内存空间的方法的解题步骤:
1.反转区间为前n的子串;2.反转区间为n到末尾的子串;3.反转整个字符串
代码实现:
方法1:申请额外的内存空间
class Solution {
public:
string reverseLeftWords(string s, int n) {
if (s.empty()) {
return "";
}
if (n < 0 || n >= s.length()) {
return s;
}
string array_front;
string array_rear;
int i = 0;
for (auto ch:s) {
if (i < n) {
array_front.push_back(ch);
} else {
array_rear.push_back(ch);
}
i++;
}
for (auto ch:array_front) {
array_rear.push_back(ch);
}
return array_rear;
}
};
方法2:不申请额外的内存空间
class Solution {
public:
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;
}
};