代码随想录第八天 LeetCode 344、541、剑指Offer 05、151、剑指Offer58 (字符串)
字符串简介
首先还是来简单介绍一下字符串,首先区别一下c++中char *、char []、string
的区别:
char *
是一个指向字符串的指针,可以直接使用字符串赋值,如char *s = "abc"
。char []
本质上是一个数组,变量名指向数组的第一个元素,如char str[5]
。另外注意字符型数组最后一个元素会存放一个\0
。例如char str[5] = {"abcde"};
是不合法的,因为末尾必须有一个\0
。string
是c++中的一个类,拥有自己封装好的类成员函数。
下面复习一下string类的一些常用函数:
//初始化
//string也是类,可以像vector以及其他的c++容器类似的方式初始化
string s1("abc");
string s2(s1);
string s3(10,'a'); //初始化10个a
string s4 = "tuboshu"; //c风格的初始化//获取长度
s1.size();
s1.length(); //两者本质上相同//添加
s1.append(s2); //go中也是这样拼接的
s1.push_back('a');
s1.insert(...); //insert函数重载有很多但是不常用到//查找
int index = s4.find("bo"); //返回一个index是"bo"字符穿首次出现的首字母的位置//删除
s4.erase(s4.begin(),s4.begin() + 2); //删除指定位置
s4.erase(2); //删除从下标2到结束的字符串
s4.erase(2,2); //删除从下标2开始长度为2的字符串//substr获取字串 substr(pos,len) pos的下标从0开始
string s5 = s4.substr(1); //获取s4的第2个元素到结束构成字串
string s6 = s4.substr(2,1); //从s4的第2个元素长度为1的字串
string s7 = s4.substr(s4.find("b"));
另外,因为重载了+
运算符,所以string类型的拼接可以直接使用运算符操作。
参考文章:C++string类常用方法。
344.反转字符串
两种方法:1.直接调用reverse()
函数
2.双指针法,两个指针分别从头尾向内收缩完成交换:
void reverseString(vector<char>& s) {int left = 0;int right = s.size()-1;while(left<right){swap(s[left++],s[right--]);}}
本题没什么好说的,可以对比一下206. 反转链表。
541. 反转字符串 II
本题翻转的逻辑和上一题一模一样,只不过在遍历字符串时需要注意一些细节,也就是模拟的过程。另外需要处理一下遍历到末尾时的特殊情况。
代码如下:
string reverseStr(string s, int k) {for(int i = 0; i < s.size(); ){//分为两种情况,一种是剩下的字符小于k,另一种是大于等于kif(s.size() - i >= k){int left = i;int right = i + k - 1;while(left < right){swap(s[left++],s[right--]);}//模拟过程的时候i每次增加2ki += 2 * k;}else{int left = i;int right = s.size() - 1;while(left < right){swap(s[left++],s[right--]);}break;}}return s;}
翻转子字符串的逻辑这里可以直接使用reverse()
函数代替更简洁。
剑指 Offer 05. 替换空格
很明显本题输出字符串的size
和输入的不同,所以有一个resize()
的操作。卡哥说不申请额外空间完成,这种类似移除元素一般用双指针法,但是本题是从后往前遍历,这样就可以避免从前往后遍历时的时间复杂度为O(n^2)。
先找出空格的个数,然后重新分配字符串长度,这里应该是原来的size加2*空格数量,因为空格本身也占用一个位置。。然后就是替换的逻辑。
代码如下:
class Solution {public:string replaceSpace(string s) {int count = 0;int size = s.size();for(int i = 0; i < s.size(); i++){if(s[i] == ' ') count++;}if(count == 0) return s;s.resize(size + count * 2);int left = size - 1;int right = s.size() - 1;while(left >= 0){if(s[left] != ' '){s[right--] = s[left--];continue;}s[right--] = '0';s[right--] = '2';s[right--] = '%';left--;}return s;}
};
151. 反转字符串中的单词
本题的确很烦人,代码看起来很简洁,实际上背后隐藏了很多逻辑和情况。
大体思路首先应该去掉多余空格,包括头尾和中间的多余空格,然后再翻转,翻转的逻辑使用先整体再部分,也是很巧妙的一种思路。
仔细想一下可以发现去除多余空格可以将所有空格全部删除,并在两个单词之间补上需要的空格,这样就不需要分开讨论了,就变成了删除字符串元素的题,再做一些特殊处理,代码如下:
int slow = 0 , fast = 0;//去空格for(;fast < s.size(); fast++){if(s[fast] != ' '){if(slow != 0) s[slow++] = ' ';while(fast < s.size() && s[fast] != ' '){s[slow] = s[fast];slow++;fast++;}}}
使用双指针法,快指针指向主要用来遍历数组,慢指针指向需要更新当前元素的位置。这里为什么要在s[fast] != ' '
里加一个while循环呢,因为进入条件后首先需要判断的是是否需要补空格,在一个完整的单词后补空格是需要移动慢指针的,所以当s[fast] != ' '
也就是遍历遇到需要保留下来的元素时,应该把一个完整的单词处理完再进入下一次循环。或者反过来想一下,如果这样写:
for(;fast < s.size(); fast++){if(s[fast] != ' '){if(slow != 0) s[slow++] = ' ';s[slow] = s[fast];slow++;fast++;}}}
这就是一个普通的移除元素的逻辑,这样会导致每次遇到一个字母都会在后面加一个空格,显然是不对的。在while循环中加入fast < s.size()
判断是防止遍历到最后一个元素时fast++
导致内存读取错误。
接下来就是部分翻转的逻辑:
//翻转int pos = 0;for(int i = 0; i < s.size(); i++){if(s[i] == ' '){reverse(s.begin() + pos, s.begin() + i);pos = i + 1;}if(i == s.size() - 1) reverse(s.begin() + pos, s.end());}
其实一开始我是这样写的:
//翻转int pos = 0;for(int i = 0; i < s.size(); i++){if(s[i] == ' '){reverse(s.begin() + pos, s.begin() + i);pos = i + 1;}}
这样会导致最后一个单词不能正常翻转,因为reverse()
函数是左闭右开的,所以另外加一个特殊处理,或者像卡哥一样自己写一个左闭右闭的reverse函数。
最后是完整的代码:
class Solution {public:string reverseWords(string s) {int slow = 0 , fast = 0;//去空格for(;fast < s.size(); fast++){if(s[fast] != ' '){if(slow != 0) s[slow++] = ' ';while(fast < s.size() && s[fast] != ' '){s[slow] = s[fast];slow++;fast++;}}}s.resize(slow);reverse(s.begin(), s.end());//翻转int pos = 0;for(int i = 0; i < s.size(); i++){if(s[i] == ' '){reverse(s.begin() + pos, s.begin() + i);pos = i + 1;}if(i == s.size() - 1) reverse(s.begin() + pos, s.end());}return s;}
};
总结一下,双指针法的思想固然重要,但是想要能一次写出AC出来的代码,对细节和多种情况的把握才是关键。
剑指Offer58-II.左旋转字符串
在空间复杂度为O(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;}
还是要注意reverse()
在翻转字符串时的效果。
代码随想录第八天 LeetCode 344、541、剑指Offer 05、151、剑指Offer58 (字符串)相关推荐
- 代码随想录算法训练营第08天 | LeetCode 344.反转字符串,541. 反转字符串2,剑指Offer 05.替换空格,151.翻转字符串里的单词,剑指Offer58-II.左旋转字符串
LeetCode [344. 反转字符串] 题目:编写一个函数,其作用是将输入的字符串反转过来.输入字符串以字符数组 s 的形式给出. 不要给另外的数组分配额外的空间,你必须**原地修改输入数组**. ...
- 代码随想录算法训练营第八天|344.反转字符串 541. 反转字符串II 剑指Offer 05.替换空格 151.翻转字符串里的单词 剑指Offer58-II.左旋转字符串
一.344.反转字符串 题目:编写一个函数,其作用是将输入的字符串反转过来.输入字符串以字符数组 char[] 的形式给出. 不要给另外的数组分配额外的空间,你必须原地修改输入数组.使用 O(1) 的 ...
- 代码随想录算法训练营第八天|● 344.反转字符串● 541. 反转字符串II● 剑指Offer 05.替换空格● 151.翻转字符串里的单词● 剑指Offer58-II.左旋转字符
一.344.反转字符串 力扣 思路:很简单的一个for循环双指针,left和right交换. class Solution {public void reverseString(char[] s) { ...
- Suzy找到实习了吗Day 8 | 字符串开始啦 344. 反转字符串,541. 反转字符串 II,剑指 Offer 05. 替换空格,151. 反转字符串中的单词,左旋转字符串
这里是目录 344. 反转字符串 题目 Solution 541. 反转字符串 II 题目 Solution(v1) Solution(v2) 剑指 Offer 05. 替换空格 做题记录 151. ...
- 《LeetCode力扣练习》剑指 Offer 05. 替换空格 Java
<LeetCode力扣练习>剑指 Offer 05. 替换空格 Java 一.资源 题目: 请实现一个函数,把字符串 s 中的每个空格替换成"%20". 示例 1: 输 ...
- 【LeetCode】剑指 Offer 46. 把数字翻译成字符串
[LeetCode]剑指 Offer 46. 把数字翻译成字符串 文章目录 [LeetCode]剑指 Offer 46. 把数字翻译成字符串 package offer;public class So ...
- 剑指 Offer 05. 替换空格(完整代码)
文章目录 剑指 Offer 05. 替换空格 1. 核心代码 2. 完整代码 总结 剑指 Offer 05. 替换空格 请实现一个函数,把字符串 s 中的每个空格替换成"%20". ...
- 字符串(一) | 剑指 Offer 58 - II. 左旋转字符串、541. 反转字符串 II、剑指 Offer 05. 替换空格、151. 反转字符串中的单词
剑指 Offer 58 - II. 左旋转字符串 把前k个字符移动到结尾 翻转前k个字符,翻转剩余字符 翻转整个字符串 class Solution { public:void reverse(str ...
- leetcode 剑指 Offer 46. 把数字翻译成字符串
剑指 Offer 46. 把数字翻译成字符串 给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 "a" ,1 翻译成 "b",--,11 翻译成 &q ...
- LeetCode 03: T58. 最后一个单词的长度(简单); 剑指 Offer 05. 替换空格(简单); 剑指 Offer 58 - II. 左旋转字符串(简单)
文章目录 T7: 58. 最后一个单词的长度(简单) 思路 解法: 双指针 T8: 剑指 Offer 05. 替换空格(简单) 思路 解法: replace T9: 剑指 Offer 58 - II. ...
最新文章
- iOS UITableView
- vim 命令_Vim 操作命令手册
- php表格怎么合并单元格格式化,table标签的结构与合并单元格的实现方法
- 官宣 | Apache Flink 1.12.0 正式发布,流批一体真正统一运行!
- WebService学习总结(3)——使用java JDK开发WebService
- 开启apache服务
- Java equalsIgnoreCase() 方法
- SunFMEA-基于AIAG-VDA-FMEA的风险管理工具
- 数字证书:签名证书加密证书
- 题解 P2212 【[USACO14MAR]浇地Watering the Fields】
- html语言中alt,html中alt的用法
- 论文笔记(五)FWENet:基于SAR图像的洪水水体提取深度卷积神经网络(CVPR)
- 一个9年运维的经验之路
- 零基础学习嵌入式入门以及项目实战开发【手把手教+国内独家+原创】
- 联合索引,组合索引,详细应用实例
- Ubuntu18.04 安装SDN ryu+mininet
- 奥运英语[5] 很高兴再次见到你 Good to see you again.
- Java小知识之海王多线程
- 多款可视化表单、流程开源设计器
- DNS_PROBE_POSSIBLE打不开网页怎么办?