leetcode-master/problems/剑指Offer05.替换空格.md

120 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 题目地址
https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof/
> 遇到对字符串或者数组做填充或删除的操作时,都要想想从后向前操作怎么样。
# 题目剑指Offer 05.替换空格
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
示例 1
输入s = "We are happy."
输出:"We%20are%20happy."
# 思路
如果想把这道题目做到极致,就不要只用额外的辅助空间了!
首先扩充数组到每个空格替换成"%20"之后的大小。
然后从后向前替换空格,也就是双指针法,过程如下:
i指向新长度的末尾j指向旧长度的末尾。
<img src='../video/替换空格.gif' width=600> </img></div>
有同学问了,为什么要从后向前填充,从前向后填充不行么?
从前向后填充就是O(n^2)的算法了,因为每次添加元素都要将添加元素之后的所有元素向后移动。
**其实很多数组填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。**
这么做有两个好处:
1. 不用申请新数组。
2. 从后向前填充元素,避免了从前先后填充元素要来的 每次添加元素都要将添加元素之后的所有元素向后移动。
时间复杂度空间复杂度均超过100%的用户。
<img src='../pics/剑指Offer05.替换空格.png' width=600> </img></div>
## C++代码
```
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;
}
};
```
时间复杂度O(n)
空间复杂度O(1)
此时算上本题,我们已经做了七道双指针相关的题目了分别是:
* [27.移除元素](https://mp.weixin.qq.com/s/wj0T-Xs88_FHJFwayElQlA)
* [15.三数之和](https://mp.weixin.qq.com/s/r5cgZFu0tv4grBAexdcd8A)
* [18.四数之和](https://mp.weixin.qq.com/s/nQrcco8AZJV1pAOVjeIU_g)
* [206.翻转链表](https://mp.weixin.qq.com/s/pnvVP-0ZM7epB8y3w_Njwg)
* [142.环形链表II](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)
* [344.反转字符串](https://mp.weixin.qq.com/s/X02S61WCYiCEhaik6VUpFA)
# 拓展
这里也给大家拓展一下字符串和数组有什么差别,
字符串是若干字符组成的有限序列也可以理解为是一个字符数组但是很多语言对字符串做了特殊的规定接下来我来说一说C/C++中的字符串。
在C语言中把一个字符串存入一个数组时也把结束符 '\0'存入数组,并以此作为该字符串是否结束的标志。
例如这段代码:
```
char a[5] = "asd";
for (int i = 0; a[i] != '\0'; i++) {
}
```
在C++中提供一个string类string类会提供 size接口可以用来判断string类字符串是否结束就不用'\0'来判断是否结束。
例如这段代码:
```
string a = "asd";
for (int i = 0; i < a.size(); i++) {
}
```
那么vector< char > 和 string 又有什么区别呢?
其实在基本操作上没有区别,但是 string提供更多的字符串处理的相关接口例如string 重载了+而vector却没有。
所以想处理字符串我们还是会定义一个string类型。
> 更多算法干货文章持续更新可以微信搜索「代码随想录」第一时间围观关注后回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等就可以获得我多年整理的学习资料。