344.反转字符串
// 普通交换
void reverse(char &lhs, char &rhs) {
char tmp = lhs;
lhs = rhs;
rhs = tmp;
}
// 位运算交换
// 1.任意一个变量X与其自身进行异或运算,结果为0,即X^X=0
// 2.任意一个变量X与0进行异或运算,结果不变,即X^0=X
// 3.异或运算具有可结合性,即a^b^c=(a^b)^c=a^(b^c)
// 4.异或运算具有可交换性,即a^b=b^a
void bitReverse(char &lhs, char &rhs) {
// 令a=lhs,b=rhs;
// a = a ^ b;
lhs ^= rhs;
// b = a ^ b;其中a = a ^ b
// b = a ^ b ^ b; 即b = a;
rhs ^= lhs;
// a = a ^ b; 其中a = a ^ b; b = a;
// a = a ^ b ^ a; a = b;
lhs ^= rhs;
}
// 时间复杂度: O(n)
// 空间复杂度: O(1)
void reverseString(vector<char>& s) {
int left = 0;
int right = s.size() - 1;
while (left < right) {
bitReverse(s[left], s[right]);
++left;
--right;
}
}
541. 反转字符串II
// 使用reverse库函数版本
// 让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否有需要反转的区间。
// O(n) O(1)
string reverseStr1(string s, int k) {
for (int i = 0; i < s.size(); i += (2 * k)) {
// 每隔2k个字符,把这个区间内的前k个字符反转
// 剩余字符小于2k个大于k个,则反转前k个字符
if (i + k < s.size()) {
reverse(s.begin() + i, s.begin() + i + k);
}
else {
reverse(s.begin() + i, s.end());
}
}
return s;
}
// swap实现的reverse0
void reverse0(string &s, int start, int end) {
for (int i = start, j = end; i < j; ++i, --j) {
swap(s[i], s[j]);
}
}
// 使用自定义reverse函数版本
// O(n) O(1)
string reverseStr2(string s, int k) {
for (int i = 0; i < s.size(); i += (2 * k)) {
if (i + k < s.size()) {
reverse0(s, i, i + k - 1);
}
else {
reverse0(s, i, s.size() - 1);
}
}
return s;
}
// other
// O(n) O(1)
string reverseStr3(string s, int k) {
int n = s.size();
int 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.替换空格
思路:见代码注释。
// 双指针法,先扩充数组,再从后往前遍历。
// 好处:不用申请新数组,避免了数组元素的移动。
string replaceSpace(string s) {
// 统计' '的个数
int blankCount = 0;
int oldSize = s.size();
for (int i = 0 ;i < oldSize; ++i) {
// 单引号而不是双引号
if (s[i] == ' ') {
++blankCount;
}
}
// 扩充数组, ' '——>'%20'
s.resize(oldSize + 2 * blankCount);
int newSize = s.size();
for (int i = oldSize - 1, j = newSize - 1; i < j; --i, --j) {
if (s[i] != ' ') {
s[j] = s[i];
}
else {
s[j] = '0';
s[j - 1] = '2';
s[j - 2] = '%';
j -= 2;
}
}
return s;
}
151.翻转字符串里的单词
思路:可以利用中的stringstream来接收和输出单词,能够简单的解决空格问题;或是把问题分解成两部分:去除空格(前,中冗余,后)和反转(整体反转后再进行单词反转)。
class Solution {
public:
// 法一:利用stringstream求解
string reverseWords(string s) {
stringstream ss;
string res = "", tmp;
ss << s;
// stringstream每次从后往前输出一个word
while (ss>>tmp) {
// 每次往res输入" " + word
res = " " + tmp + res;
}
// 如果res不为空字符串
if (res != "") {
// 删除字符串开头的空格
res.erase(res.begin());
}
return res;
}
// 法二:不适用额外内存空间,保持O(1)
// 先删除额外的空格,再倒序,思路如下:
// 1、移除多余空格
// 2、将整个字符串反转
// 3、将每个单词反转
// 遍历多余空格,erase删除
// erase本身是O(n)操作
// for套erase就是O(n^2)
void removeExtraSpaces1(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());
}
}
// 双指针移除空格,最后resize字符串大小
// O(n)
void removeExtraSpaces2(string& s) {
// 定义快慢指针
int slow = 0, fast = 0;
// 去掉字符串前面的空格
while (s.size() > 0 && fast < s.size() && s[fast] == ' ') {
fast++;
}
// 去掉字符串中间部分的冗余空格
for (; fast < s.size(); ++fast) {
if (fast - 1 > 0
&& s[fast - 1] == s[fast]
&& s[fast] == ' '
)
{
continue;
} else {
s[slow++] = s[fast];
}
}
// 去掉字符串后面的空格
if (slow - 1 > 0 && s[slow - 1] == ' ') {
s.resize(slow - 1);
} else {
s.resize(slow);
}
}
// 快慢指针,去除所有空格然后在相邻单词之间添加空格
void removeExtraSpaces3(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);
}
// 反转字符串
void reverse(string& s, int start, int end) {
for (int i = start, j = end; i < j; i++, j--) {
swap(s[i], s[j]);
}
}
string reverseWords2(string s) {
// 步骤一
removeExtraSpaces3(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;
}
};
题目:剑指Offer58-II.左旋转字符串
//反转区间为前n的子串
//反转区间为n到末尾的子串
//反转整个字符串
string reverseLeftWords(string s, int n) {
// reverse()反转 [first, last) 范围中的元素顺序
// 左闭右开区间
reverse(s.begin(), s.begin() + n);
reverse(s.begin() + n, s.end());
reverse(s.begin(), s.end());
return s;
}
string reverseLeftWords2(string s, int n) {
string sub1 = s.substr(0, n);
string sub2 = s.substr(n, s.size() - n);
string res = sub1 + sub2;
return res;
}