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

news2024/12/29 10:31:23

字符串翻转合集

  • 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++;
                    };
            }
            //如果不是空格就保留
            else
                s[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;
            }
        }   
        //反转整个字符串s
        reverse(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,剩下的字符看成单词1,那就是把单词1和单词2交换顺序,单词内容的字符顺序是不变的。
代码如下(C++):

class Solution {
public:
    string reverseLeftWords(string s, int n) {
    	//反转单词1
        reverse(s.begin(), s.begin() + n);
        //反转单词2
        reverse(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在后半段就右移
        else
            right_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.coloradmin.cn/o/937662.html

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

相关文章

Java --- 异常处理

目录 一、什么是异常 二、异常抛出机制 三、如何对待异常 四、 Java异常体系 4.1、Throwable 4.2、Error 4.2、Exception 4.2.1、编译时异常 4.2.2、运行时期异常 五、异常处理 5.1、捕获异常&#xff08;try-catch&#xff09; 5.1.2、catch中异常处理方式 …

顺序表链表OJ题(1)——【LeetCode】

W...Y的主页 &#x1f60a; 代码仓库分享 &#x1f495; 前言&#xff1a; 今天我们来回顾一下顺序表与链表&#xff0c;针对这一块我们也有许多OJ题目供大家参考。当我们学习完顺序表链表后避免不了一些习题的练习&#xff0c;这样才能巩固我们学习的内容。 话不多说&#xf…

C++:常成员变量、常成员函数、常对象

常成员变量: 1.用const修饰&#xff0c;可位于类型前后&#xff0c;若是成员变量类型为指针则只可位于类型后。 即&#xff1a;int *const p&#xff1b; 2.只能通过构造函数的初始化表对常成员变量进行初始化。 3.常成员所在类中的所有构造函数都必须对常成员变量初始化…

06.sqlite3学习——DQL(数据查询)(全)

目录 SQLite——DQL&#xff08;数据查询&#xff09; 数据集 select语句 条件查询 比较 确定范围 确定集合 like 查询记录 查询不重复的记录 排序和限制 排序 限制 聚合 聚合函数 语法 SQLite Group By详解 语法 实例 SQLite Having 子句 语法 实例 多…

浪潮云海护航省联社金融上云,“一云多芯”赋能数字农业

农村金融是现代金融体系的重要组成部分&#xff0c;是农业农村发展的重要支撑力量&#xff0c;而统管全省农商行及农信社的省级农村信用社联合社&#xff08;以下简称&#xff1a;省联社&#xff09;在我国金融系统中占据着举足轻重的地位。省联社通常采用“大平台小法人”的发…

Leetcode 2651.计算列车到站时间

给你一个正整数 arrivalTime 表示列车正点到站的时间&#xff08;单位&#xff1a;小时&#xff09;&#xff0c;另给你一个正整数 delayedTime 表示列车延误的小时数。 返回列车实际到站的时间。 注意&#xff0c;该问题中的时间采用 24 小时制。 示例 1&#xff1a; 输入&…

计算机系统真题

计算机系统真题 考点计算机系统存储体系磁盘调度算法 考点 计算机系统 PC找到指令&#xff0c;存储到IR中 根据ID分析指令的操作&#xff0c;并执行指令,AR访问操作数 A pc存指令的地址 内存按照字节编址&#xff1a; 在统一单位&#xff0c;转换一下&#xff1a; 3x2的平方 …

飞腾E2000 UEFI使用设备树方式启动linux系统

以往我们使用uboot引导系统启动,是采用uboot引导设备树+内核+文件系统的方式。 那么使用UEFI如何通过设备树+内核+文件系统的方式进行引导呢?这篇文章主要就介绍了这种操作方法。 一、使用Buildroot交叉编译生成E2000 Linux系统 详细请参考嵌入式软件部提供的 E2000 Linux…

服务器部署前后端项目-SQL Father为例

hello~大家好哇&#xff0c;好久没更新博客了。现在来更新一波hhh 现在更新一下部署上的一些东西&#xff0c;因为其实有很多小伙伴跟我之前一样&#xff0c;很多时候只是开发了&#xff0c;本地前后端都能调通&#xff0c;也能用&#xff0c;但是没有部署到服务器试过&#x…

【FPGA零基础学习之旅#11】数码管动态扫描

&#x1f389;欢迎来到FPGA专栏~数码管动态扫描 ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;FPGA学习之旅 文章作者技术和水平有限&#xff0c;如果文中出现错误&#xff0c;希望大家能指正…

React笔记(二)JSX

一、JSX JSX是javascript XML的简写&#xff0c;实际上是javascript的扩展&#xff0c;既有javascript的语法结构&#xff0c;又有XML的结构 1、JSX的规则要求 jsx必须要有一个根节点 如果不想产生无用的根标签&#xff0c;但是还要遵守JSX的语法的要求&#xff0c;可以使用…

Angular中使用drag and drop实现文件拖拽上传,及flask后端接收

效果&#xff1a;拖拽文件到组件上面时 边框变大变红 松手后发送到服务器(或者点击蓝字手动选择文件)并且把文件名显示在框内&#xff0c;美化还没做 html <div class"drapBox"><div id"drop" (dragenter)"dragenter($event)" (dragov…

AR界安卓在中国,Rokid引爆空间计算狂潮

击关注 文丨刘雨琦 你可能很难想象&#xff0c;在一个没有显示屏也没有鼠标的空间&#xff0c;仅凭一副AR眼镜和一台口袋主机&#xff0c;就能完成一篇5000字的文章。 没错&#xff0c;8月26日&#xff0c;在2023 Rokid Jungle 新品发布会现场&#xff0c;这样的场景正在真实…

前端如何走通后端接口

0 写在前面 现在基本都是前后端分离的项目了&#xff0c;那么前端小伙伴如何获取后端小伙伴接口呢&#xff1f; 1 条件 同一WiFi下&#xff0c;让后端小伙伴分享出自己的ip地址&#xff1a; 步骤1:winr调出运行界面 步骤2&#xff1a;cmd调出命令行窗口 步骤3&#xff1a;…

6. 激活层

6.1 非线性激活 ① inplace为原地替换&#xff0c;若为True&#xff0c;则变量的值被替换。若为False&#xff0c;则会创建一个新变量&#xff0c;将函数处理后的值赋值给新变量&#xff0c;原始变量的值没有修改。 import torch from torch import nn from torch.nn import …

第一次实验:Protocol Layers

第一次实验&#xff1a;Protocol Layers 捕获跟踪*Pick a URL and fetch it with* wget *or* curl*.* 检查跟踪数据包结构协议开销复用密钥*Which Ethernet header field is the demultiplexing key that tells it the next higher layer is IP?**Which IP header field is th…

关于亚马逊云科技云技能孵化营学习心得

1、活动介绍 本活动主要是面向想要全面了解亚马逊云科技 (Amazon Web Services) 云的个人&#xff0c;而不受特定技术角色的限制。内容包括亚马逊云科技云概念、亚马逊云科技服务、安全性、架构、定价和支持等等&#xff0c;此外还可以参加亚马逊的认证考试。 2、学习过程 该…

httpd协议与apache

1.http 相关概念 HTTP是处于应用层的协议&#xff0c;使用TCP传输层协议进行可靠的传送。因此&#xff0c;需要特别提醒的是&#xff0c;万维网是基于因特网的一种广泛因特网应用系统&#xff0c;且万维网采用的是HTTP&#xff08;80/TCP&#xff09;和 HTTPS&#xff08;443/…

计算机毕设 基于深度学习的人脸专注度检测计算系统 - opencv python cnn

文章目录 1 前言2 相关技术2.1CNN简介2.2 人脸识别算法2.3专注检测原理2.4 OpenCV 3 功能介绍3.1人脸录入功能3.2 人脸识别3.3 人脸专注度检测3.4 识别记录 4 最后 1 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新…

Autoware.universe部署02:高精Lanelet2地图的绘制

文章目录 引言Lanelet基础元素Lanelet2项目各个模块 一、安装Lanelet2项目1.1 安装依赖1.2 编译1.3 在ROS中使用lanelet2地图完成routing 二、Autoware Vector Map Builder绘制高精地图2.1 创建地图2.2 绘制车道线2.3 绘制路沿2.4 绘制停止线和交通灯2.5 绘制人行道2.6 绘制停车…