字符串简介

首先还是来简单介绍一下字符串,首先区别一下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 (字符串)相关推荐

  1. 代码随想录算法训练营第08天 | LeetCode 344.反转字符串,541. 反转字符串2,剑指Offer 05.替换空格,151.翻转字符串里的单词,剑指Offer58-II.左旋转字符串

    LeetCode [344. 反转字符串] 题目:编写一个函数,其作用是将输入的字符串反转过来.输入字符串以字符数组 s 的形式给出. 不要给另外的数组分配额外的空间,你必须**原地修改输入数组**. ...

  2. 代码随想录算法训练营第八天|344.反转字符串 541. 反转字符串II 剑指Offer 05.替换空格 151.翻转字符串里的单词 剑指Offer58-II.左旋转字符串

    一.344.反转字符串 题目:编写一个函数,其作用是将输入的字符串反转过来.输入字符串以字符数组 char[] 的形式给出. 不要给另外的数组分配额外的空间,你必须原地修改输入数组.使用 O(1) 的 ...

  3. 代码随想录算法训练营第八天|● 344.反转字符串● 541. 反转字符串II● 剑指Offer 05.替换空格● 151.翻转字符串里的单词● 剑指Offer58-II.左旋转字符

    一.344.反转字符串 力扣 思路:很简单的一个for循环双指针,left和right交换. class Solution {public void reverseString(char[] s) { ...

  4. Suzy找到实习了吗Day 8 | 字符串开始啦 344. 反转字符串,541. 反转字符串 II,剑指 Offer 05. 替换空格,151. 反转字符串中的单词,左旋转字符串

    这里是目录 344. 反转字符串 题目 Solution 541. 反转字符串 II 题目 Solution(v1) Solution(v2) 剑指 Offer 05. 替换空格 做题记录 151. ...

  5. 《LeetCode力扣练习》剑指 Offer 05. 替换空格 Java

    <LeetCode力扣练习>剑指 Offer 05. 替换空格 Java 一.资源 题目: 请实现一个函数,把字符串 s 中的每个空格替换成"%20". 示例 1: 输 ...

  6. 【LeetCode】剑指 Offer 46. 把数字翻译成字符串

    [LeetCode]剑指 Offer 46. 把数字翻译成字符串 文章目录 [LeetCode]剑指 Offer 46. 把数字翻译成字符串 package offer;public class So ...

  7. 剑指 Offer 05. 替换空格(完整代码)

    文章目录 剑指 Offer 05. 替换空格 1. 核心代码 2. 完整代码 总结 剑指 Offer 05. 替换空格 请实现一个函数,把字符串 s 中的每个空格替换成"%20". ...

  8. 字符串(一) | 剑指 Offer 58 - II. 左旋转字符串、541. 反转字符串 II、剑指 Offer 05. 替换空格、151. 反转字符串中的单词

    剑指 Offer 58 - II. 左旋转字符串 把前k个字符移动到结尾 翻转前k个字符,翻转剩余字符 翻转整个字符串 class Solution { public:void reverse(str ...

  9. leetcode 剑指 Offer 46. 把数字翻译成字符串

    剑指 Offer 46. 把数字翻译成字符串 给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 "a" ,1 翻译成 "b",--,11 翻译成 &q ...

  10. LeetCode 03: T58. 最后一个单词的长度(简单); 剑指 Offer 05. 替换空格(简单); 剑指 Offer 58 - II. 左旋转字符串(简单)

    文章目录 T7: 58. 最后一个单词的长度(简单) 思路 解法: 双指针 T8: 剑指 Offer 05. 替换空格(简单) 思路 解法: replace T9: 剑指 Offer 58 - II. ...

最新文章

  1. iOS UITableView
  2. vim 命令_Vim 操作命令手册
  3. php表格怎么合并单元格格式化,table标签的结构与合并单元格的实现方法
  4. 官宣 | Apache Flink 1.12.0 正式发布,流批一体真正统一运行!
  5. WebService学习总结(3)——使用java JDK开发WebService
  6. 开启apache服务
  7. Java equalsIgnoreCase() 方法
  8. SunFMEA-基于AIAG-VDA-FMEA的风险管理工具
  9. 数字证书:签名证书加密证书
  10. 题解 P2212 【[USACO14MAR]浇地Watering the Fields】
  11. html语言中alt,html中alt的用法
  12. 论文笔记(五)FWENet:基于SAR图像的洪水水体提取深度卷积神经网络(CVPR)
  13. 一个9年运维的经验之路
  14. 零基础学习嵌入式入门以及项目实战开发【手把手教+国内独家+原创】
  15. 联合索引,组合索引,详细应用实例
  16. Ubuntu18.04 安装SDN ryu+mininet
  17. 奥运英语[5] 很高兴再次见到你 Good to see you again.
  18. Java小知识之海王多线程
  19. 多款可视化表单、流程开源设计器
  20. DNS_PROBE_POSSIBLE打不开网页怎么办?

热门文章

  1. input-group两侧添加额外元素
  2. SpringBoot整体开发的详细过程(待完结)
  3. java类的使用方法小结_JavaPoet的使用指南小结
  4. Android Studio 中使用 Git
  5. Python(高级FTP作业)
  6. 网易微专业大数据工程师
  7. Linux之CD驱动器读取命令
  8. linux防护勒索病毒的补丁,抵御Petya勒索病毒的最新办法
  9. 计算机主机配置一般有机箱主板cpu,组装台式电脑配置清单
  10. 情绪满盈,心猿似马,人生80%的时间都在自我内耗