【leetcode 力扣刷题】字符串翻转合集(全部反转///部分反转)

字符串翻转合集

  • 344. 反转字符串
  • 541. 反转字符串Ⅱ
  • 151. 反转字符串中的单词
  • 剑指 Offer 58 - II. 左旋转字符串
    • 反转单词思路
    • 循环挪动
    • 子串和子串的拼接

344. 反转字符串

题目链接:344. 反转字符串
题目内容:
在这里插入图片描述
题目中重点强调了必须原地修改输入数组,即不能新建一个数组来完成字符串的反转。我们注意到:

  • 原来下标为0的,反转后是size - 1【原来下标是size - 1的,反转后是0】;
  • 原来下标是1的,反转后是size - 2【原来下标是size -2的,反转后是1】;
  • ……原来下标是i的,反转后变成了size - 1 - i【原来下标是size - 1 - i的,反转后是i】

因此可以用双指针,front = 0,behind = size -1;front向后移动,behind向前移动;front和behind对应元素交换位置即完成字符串的反转。交换元素需要额外申请一个元素的空间,因此空间复杂度是O(1)的。
代码如下(C++):

class Solution {
public:void reverseString(vector<char>& s) {int n = s.size();//双指针for(int front = 0, behind = n - 1; front < behind ; front++, behind--){//交换front、behind对应位置的元素char tmp = s[front];s[front] =s[behind];s[behind] = tmp;}return ;}
};

注意,这道题是考察反转字符串实现的逻辑,如果用reverse函数反转就失去了考察的意义。

541. 反转字符串Ⅱ

题目链接:541. 反转字符串Ⅱ
题目内容:
在这里插入图片描述
题目意思是,将字符串s分组

  • 每一组包括2k个字符;
  • 每一组里面反转前k个字符,后面k个字符位置不变;
  • 对于最后一组,要是少于k个字符,那全部反转;要是在k~2k之间,照样反转前k个字符;

怎么实现分组呢?用start表示每组开始的下标,start从0开始,每次+2k。这里的反转每组前k个字符,可以直接调用reverse函数,也可以自己写一个反转的函数。
代码如下(C++):


class Solution {
public://自己定义的反转[start,end)间字符的函数void myReverse(string& s, int start, int end){for(int i = start, j = end -1; i < j; i++, j--)swap(s[i],s[j]);}string reverseStr(string s, int k) {int n = s.size();//遍历所有分组for(int start = 0; start < n ; start += 2*k){//判断前k个元素是否越界if(start + k < n) //反转前k个元素myReverse(s, start, start + k);//替换成内置函数 reverse(s.begin() + i, s.begin() + i + k);也可以else //反转最后剩余的不足k的元素   myReverse(s, start, n);//替换成内置函数 reverse(s.begin() + i, s.end());也可以}return s;}
};

151. 反转字符串中的单词

题目链接:151. 反转字符串中的单词
题目内容:
在这里插入图片描述
根据题目描述和示例,可以知道,所谓的反转单词,是反转单词间的顺序,但是单词内部的字符顺序是不变的。另外还需要处理多余的空格——最前面、最后面的空格需要全部删除;单词间的空格只保留一个。
首先处理掉多余的空格,再进行单词顺序的翻转。移除多余的空格,参考27. 移除元素,直接使用双指针,原地操作,移除掉多余空格后,s有效长度是小于等于实际长度的,resize一下就好。
一开始我的移除空格逻辑是:①第一个单词前,所有的空格都移除掉:用while,直到s[fats] != ‘ ’结束;②单词间的空格只保留一个,如果s[fast] == ‘ ’但是前面一个字符s[fast-1] != ‘ ’那么这个空格就保留,其他的就全部删除;③由于第二步,最后一个单词后如果有大于等于一个空格,最后会保留一个,最终是要把这个删除掉的。 当然过程中s[fast] != ‘ ’,就直接保留。【整体是双指针原地移动】
删除多余空格代码Ⅰ(C++):

  		int fast;int count= 0;  //统计移除多余空格后的字符串长度,同样可以当slow指针用//删除前导空格,找到第一个单词起始的字符for(fast = 0; fast < n && s[fast] == ' ' ; )fast++;  while(fast<n){//如果是空格if(s[fast] == ' '){ //前面一个字符不是空格,那么这个空格保留作为单词间的分隔符if(s[fast-1]!=' ') s[count++] = s[fast++];else//否则就删掉空格,并且向后移动直到定位到不是空格的字符处while(fast < n && s[fast] == ' '){fast++;};}//如果不是空格就保留elses[count++] = s[fast++];}//处理最后个单词后可能保留的一个空格if(s[count-1]==' ') count--;s.resize(count);

另外一个删除多余空格的逻辑,重点是针对s[fast] != ‘ ’进行分类讨论。直接从头开始遍历s,如果s[fast] != ‘ ’,就是找到了单词,应该直接保留:①slow == 0,表示这是第一个单词开始,单词前不能有空格,那么从当前的s[fast] != ‘ ’开始,一直到s[fast] == ‘ ’结束,中间的单词字符全都保留;②如果slow != 0,说明这不是第一个单词,当前单词和前面单词间需要有一个空格,那么先添加一个空格,再加入当前单词。
代码如下(C++):

        int slow = 0;for(int fast = 0; fast < s.size() ; fast++){ //如果不是空格,就是单词if(s[fast] != ' '){//如果slow不等于0,表示不是第一个单词,单词前需要加空格if(slow!=0) s[slow++] = ' ';   //找完这个单词全部字符,直到遇到空格             while(fast < s.size() && s[fast]!=' ')s[slow++] = s[fast++];}}s.resize(slow); //slow表示指针也统计字符数

接下来解决怎么反转单词间的顺序?

  • 1、反转整个字符串【已经移除了多余空格了】,这个时候不仅单词的顺序已经反转了,单词内部的字符顺序也反转了;
  • 2、反转单词内字符的顺序,变成原始的顺序;

经过上面两步全部反转和单词内部反转就能实现单词顺序的反转,这两步是可以交换顺序的。实现的时候定义一个start表示单词的开始,end找到空格或者移动到string外,表示单词结束,反转[start,end)间的字符;end+1,即空格后下一个字符,又是下一个单词的开始。整体代码如下(C++):

class Solution {
public://自定义一个移除多余空格的函数void Remove_Spaces(string& s){int slow = 0;for(int fast = 0; fast < s.size() ; fast++){if(s[fast] != ' '){if(slow!=0) s[slow++] = ' ';                while(fast < s.size() && s[fast]!=' ')s[slow++] = s[fast++];}}s.resize(slow);}string reverseWords(string s) {Remove_Spaces(s); //先移除多余空格int start = 0;//反转单词间字符顺序for(int end = 0;  end <= s.size() ; end++){//遇到空格反转前面一个单词if(end == s.size() || s[end] == ' '){reverse(s.begin()+start, s.begin()+end);//下一个单词的开始start = end+1;}}   //反转整个字符串sreverse(s.begin(), s.end());return s;}
};

代码中需要注意if(end == s.size() || s[end] == ‘ ’),实际上对于||和&&这样的逻辑运算是短路运算的。在A||B中,如果A已经为true了整个表达式是true的,B不需要判断了;在A&&B中,如果A已经是false了整个表达式是false的,B也不需要判断了。式子end == s.size() || s[end] == ‘ ’需要把end == s.size() 写在前面,如果把s[end] == ‘ ’写在前面而end = s.size()的话,就会出现下标越界。

剑指 Offer 58 - II. 左旋转字符串

题目链接:剑指 Offer 58 - II. 左旋转字符串
题目内容:
在这里插入图片描述

反转单词思路

理解题意,其实和上一题反转单词是一样的思路,把前k个字符看成单词1,剩下的字符看成单词2,那就是把单词1和单词2交换顺序,单词内容的字符顺序是不变的。
代码如下(C++):

class Solution {
public:string reverseLeftWords(string s, int n) {//反转单词1reverse(s.begin(), s.begin() + n);//反转单词2reverse(s.begin() + n, s.end());//整体反转,最终只反转了单词1和单词2的顺序reverse(s.begin(), s.end());return s;}
};

分析时间复杂度:reverse是O(n)的,三次reverse最终的时间复杂度也是O(n)的。

循环挪动

根据示例我们可以看出,这个左旋的过程,可以看做是把字符串向左移动k个位置,而下标越界的部分【就是往左多出来的部分】移动到尾部。这个过程可以通过①整个字符串向左移动1个位置,第一个位置移动到末尾;②循环移动k次。
注意,如果k等于size-1呢?时间复杂度变成了O(n^2)了。对于k大于了size/2的情况,右边部分更短,考虑将整个字符串向右移,右边第一个元素移动到字符串头部,移动size-k次。 整体的时间复杂度是O(nk)或者O(n(size-k))的。比上一种解法时间复杂度更高。
代码如下(C++):

class Solution {
public:void left_move(string& s, int k){ //循环左移for(int i = 0; i < k; i++){char tmp = s[0];int j;for(j = 0; j < s.size() - 1; j++)s[j] = s[j+1];s[j] = tmp;}}void right_move(string& s, int k){ //循环右移int n = s.size();for(int i = 0; i < k; i++){char tmp = s[n-1];int j;for(j = n-1; j > 0; j--)s[j] = s[j-1];s[j] = tmp;}}string reverseLeftWords(string s, int n) {//如果n在前半段就循环左移if(n <= s.size()/2)     left_move(s, n);//n在后半段就右移elseright_move(s, s.size() - n);return s;       }
};

这个解题逻辑是没有问题的,但是当n很大的是,时间复杂度很高,以下是运行结果:
在这里插入图片描述

子串和子串的拼接

还有一种办法是把前面半截用新的string变量保存,然后拼接起来。代码如下(C++):

class Solution {
public:string reverseLeftWords(string s, int n) {string sub = s.substr(0, n);for(int i = 0; i < s.size() - n; i++)s[i] = s[i+n];for(int i = s.size() -n, j = 0; i < s.size() && j < n; i++, j++)s[i] = sub[j] ;  return s;}
};

这个时间复杂度也是O(n)的,但是需要额外的空间保存前半截子串。
总结还是第一种方法最优。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/59897.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023_Spark_实验三:基于IDEA开发Scala例子

一、创建一个空项目&#xff0c;作为整个项目的基本框架 二、创建SparkStudy模块&#xff0c;用于学习基本的Spark基础 三、创建项目结构 1、在SparkStudy模块下的pom.xml文件中加入对应的依赖&#xff0c;并等待依赖包下载完毕。 在pom.xml文件中加入对应的依赖 ​<!-- S…

理论转换实践之keepalived+nginx实现HA

背景&#xff1a; keepalivednginx实现ha是网站和应用服务器常用的方法&#xff0c;之前项目中单独用nginx实现过负载均衡和服务转发&#xff0c;keepalived一直停留在理论节点&#xff0c;加之最近工作编写的一个技术文档用到keepalived&#xff0c;于是便有了下文。 服务组件…

基于MyBatis注解的学生管理程序--mybatis注解开发的练手项目

基于MyBatis注解的学生管理程序 需求&#xff1a;完成基于MyBatis注解的学生管理程序&#xff0c;能够用MyBatis注解实现查询操作、实现修改操作、实现一对多查询 &#xff08;1&#xff09;MyBatis注解开发实现查询操作。根据表1和表2在数据库分别创建一个学生表tb_student和…

论文笔记: One Fits All:Power General Time Series Analysis by Pretrained LM

1 intro 时间序列领域预训练模型/foundation 模型的研究还不是很多 主要挑战是缺乏大量的数据来训练用于时间序列分析的基础模型——>论文利用预训练的语言模型进行通用的时间序列分析 为各种时间序列任务提供了一个统一的框架 论文还调查了为什么从语言领域预训练的Transf…

ubuntu 挂载硬盘操作

1. 查看磁盘 sudo fdisk -l 2. 查看UUID sudo blkid记录下待挂载硬盘的UUID, 后面要使用 ps. 如果报错&#xff0c;检查是否已格式化硬盘 查看新硬盘的盘符&#xff0c;我的是/dev/sda&#xff0c;用下述命令格式化 sudo mkfs -t ext4 /dev/sda3. 创建挂载点 我的是在/mnt…

C语言控制语句——分支语句

条件语句用来根据不同的条件来执行不同的语句&#xff0c;C语言中常用的条件语句包括if语句和switch语句。 if 语句 语法格式&#xff1a; if (条件) {条件成立时&#xff0c;要做的事…… }案例需求&#xff1a; 定义一个整数变量记录年龄判断是否满 18 岁 &#xff08;>…

dart 学习 之 同步生成器(sync*)和 异步生成器(async*)

同步生成器&#xff08;sync*&#xff09;和异步生成器&#xff08;async*&#xff09;都是 Dart 中用于逐步产生多个值的生成器类型&#xff0c;但它们之间有一些重要的区别&#xff1a; 执行方式&#xff1a; 同步生成器&#xff08;sync*&#xff09;&#xff1a; 同步生成器…

本地docker registry 搭建

#!/bin/bash DOCKER_REGISTRY_ROOT/data0/docker/registry DOMAINexample.host.com #生成证书&#xff1a;https://goharbor.io/docs/2.6.0/install-config/configure-https/ mkdir $DOCKER_REGISTRY_ROOT/certs cd $DOCKER_REGISTRY_ROOT/certs openssl genrsa -out ca.key 40…

[Agent]-----MRKLAgentForChatModels组件开发

参考资料&#xff1a; https://python.langchain.com/docs/modules/agents/agent_types/react https://python.langchain.com/docs/modules/agents/how_to/custom_mrkl_agent https://python.langchain.com/docs/modules/agents/how_to/mrkl 该agent主要使用ReAct框架来决定操作…

stm32之24.RTC闹钟usart端口修改配置

&#xff08;需要修改&#xff09; 源码 while(1){//rtc唤醒事件if(g_rtc_wakeup_event){//获取日期RTC_GetDate(RTC_Format_BCD,&RTC_DateStructure);printf("20%02x/%02x/%02xWeek:%x\r\n",RTC_DateStructure.RTC_Year,RTC_DateStructure.RTC_Month,RTC_Date…

d3dx9_35.dll丢失怎么解决

今天&#xff0c;我将为大家介绍关于电脑d3dx9_35.dll丢失的4种详细修复方法。希望通过这次分享&#xff0c;能够帮助大家解决在日常工作和生活中遇到的一些问题。 首先&#xff0c;让我们来了解一下d3dx9_35.dll是什么&#xff1f; d3dx9_35.dll是一个非常重要的动态链接库文…

vue2 自定义指令实现可移动模态框效果

vue2 自定义指令实现可移动模态框效果 此效果通过 vue 指令方式实现任意元素可拖拽移动。 参考官网指令介绍 https://v2.cn.vuejs.org/v2/guide/custom-directive.html 在 drag.js 文件中使用 Vue.directive() 注册一个全局自定义指令 v-drag import Vue from vue; // 1.参数一…

openGauss学习笔记-51 openGauss 高级特性-列存储

文章目录 openGauss学习笔记-51 openGauss 高级特性-列存储51.1 语法格式51.2 参数说明51.3 示例 openGauss学习笔记-51 openGauss 高级特性-列存储 openGauss支持行列混合存储。行存储是指将表按行存储到硬盘分区上&#xff0c;列存储是指将表按列存储到硬盘分区上。 行、列…

python-数据可视化-下载数据-CSV文件格式

数据以两种常见格式存储&#xff1a;CSV和JSON CSV文件格式 comma-separated values import csv filename sitka_weather_07-2018_simple.csv with open(filename) as f:reader csv.reader(f)header_row next(reader)print(header_row) # [USW00025333, SITKA AIRPORT, A…

大学生毕业设计论文题目大全_kaic

纪录片《琴书风韵》纪录片《中正安舒&#xff0c;太极明德》纪录片《茶道》纪录片《晨钟暮鼓》都福IP网络剧《梦华录》的传播策略分析新媒体时代NBA篮球文化传播对CBA的启示研究抖音账号《新闻联播》的舆论引导力构建虚拟现实技术在央视春晚中的创新实践及意义音乐综艺《乐队的…

C++中的运算符总结(8):运算符的优先级

C中的运算符总结&#xff08;8&#xff09;&#xff1a;运算符的优先级 您可能在学校学过算术运算顺序口诀 BODMAS&#xff08; Brackets Orders Division Multiplication Addition Subtraction&#xff0c;先括号&#xff0c;后乘除&#xff0c;再加减&#xff09;&#xff0…

Langchain+LLM

LangChain是一个开源框架&#xff0c;允许开发人员在与人工智能&#xff08;AI&#xff09;一起工作时将大型语言模型&#xff08;如GPT4&#xff09;与外部计算和数据源相结合&#xff08;它提供了一套工具、组件和接口&#xff0c;可简化创建由LLM提供支持的应用程序&#xf…

JavaSE 集合框架及背后的数据结构

目录 1 介绍2 学习的意义2.1 Java 集合框架的优点及作用2.2 笔试及面试题 3 接口 interfaces3.1 基本关系说明3.2 Collection 常用方法说明3.3 Collection 示例3.4 Map 常用方法说明3.5 Map 示例 4 实现 classes5 Java数据结构知识体系5.1 目标5.2 知识点 1 介绍 集合&#xf…

软件架构知识点

常用软件架构模型分类&#xff08;5种&#xff09; 软件架构建模方法&#xff08;模型4种&#xff09; 架构师分类&#xff08;微软4种&#xff09; 系统架构设计师的角色特质&#xff08;6种&#xff09; 计算机系统组成图谱 嵌入式操作系统的特点&#xff08;5个&#x…

C#_多线程编程入门

字面理解&#xff1a;多个线程同时工作的过程。 案例① 单线程 #region ① 单线程做菜/// <summary>/// ① 单线程做菜:执行任务时,什么操作都动不了./// </summary>/// <param name"sender"></param>/// <param name"e">…