代码随想录--字符串习题总结

news2024/9/24 7:20:28

代码随想录–字符串习题总结

1.LeetCode344 反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

示例 1:
输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]

解题思路: 直接使用双指针,分别从数组的第一个和最后一个元素进行遍历,然后交换这两个元素即可。

public void reverseString(char[] s) {
    int left = 0, right = s.length - 1;
    while (left < right) {
        char temp = s[left];
        s[left++] = s[right];
        s[right--] = temp;
    }
}

2.LeetCode541 反转字符串II

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。

如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

示例 1:
输入:s = "abcdefg", k = 2
输出:"bacdfeg"
示例 2:
输入:s = "abcd", k = 2
输出:"bacd"

解题思路: 这个题不涉及什么算法,只是复杂逻辑的模拟。

  • 首先要明确的是,这道题中遍历字符串,是以2k个单位进行遍历的。
  • 我们写一个循环,来遍历整个字符串,进入循环后首先需要计算剩余元素的个数s.length() - i,后续我们会根据剩余元素的个数来判断是否执行不同的逻辑
  • 如果剩余元素的个数是>=2k的,那么之间反转前k个元素即可reverseStr(chars, i, i + k - 1), 然后i移动,遍历下一个2k区间
  • 如果剩余元素个数位于[k,2k)区间内,则依然遍历前k个元素即可reverseStr(chars, i, i + k - 1),只不过直接break掉循环就可以了,因为后面也不可能在凑够2k个元素了,所以循环到这里直接终止就可以了
  • 如果剩余元素<k,则直接将剩余的所有元素反转即可reverseStr(chars, i, chars.length - 1),同理反转完成后也可以直接break掉
public static String reverseStr(String s, int k) {
    char[] chars = s.toCharArray();
    // 开始循环遍历字符串
    for (int i = 0; i < s.length() - 1;) {
        // 计算当前剩余元素个数
        int count = s.length() - i;
        // 判断是否满足2k的条件
        if (2 * k <= count) {
            // 反转前k个元素
            // TODO 反转
            reverseStr(chars, i, i + k - 1);
            i = i + 2 * k;
        } else if (count < 2 * k && count >= k) {
            // TODO 反转前k个
            reverseStr(chars, i, i + k - 1);
            break;
        } else if (count < k) {
            // TODO 反转剩余元素
            reverseStr(chars, i, chars.length - 1);
            break;
        }
    }
    return new StringBuffer().append(chars).toString();
}

private static void reverseStr(char[] chars, int start, int end) {
    while (start < end) {
        char temp = chars[start];
        chars[start++] = chars[end];
        chars[end--] = temp;
    }
}

image-20230120160851580

这个题还需要注意Java中String和char[]的互相转换

String 转 char[]

char[] chars = str.toCharArray();

char[] 转 String 需要借助StringBuilder

String str = new StringBuffer().append(chars).toString();

3. 剑指offer05 替换空格

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

示例 1:
输入:s = "We are happy."
输出:"We%20are%20happy."

解题思路1: 直接使用StringBuilder,遍历数组,只要发现有空格,就向StringBuilder中append%20,否则就把原来字符串中字符append。

public static String replaceSpace(String s) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < s.length(); i++) {
        // 这个地方比较的是字符相等不相等
        // if (" ".equals(s.charAt(i)))
        if (s.charAt(i) == ' ') {
            sb.append("%20");
            continue;
        }
        sb.append(s.charAt(i));
    }
    return sb.toString();
}

这个地方需要注意这个条件" ".equals(s.charAt(i))使用charAt(i)函数返回的是一个char,因此应该用==而不是equal方法

解题思路2: 使用双指针

  • 首先遍历整个字符串,统计空格个数
  • 然后按照空格个数,将字符串进行扩容
  • 然后i,j指针分别指向扩容前数组最后的元素,和扩容后数组的元素
  • 然后开始遍历,如果s[i]不是空格,则s[j] = s[i]
  • 如果是空格,则s[i] = '0';s[i - 1] = '2';s[i - 2] = '%';
  • 直到i==j停止循环。

image-20230120164523735

因为在Java中字符串是一个常量,我们没有办法像C++一样直接修改字符串中的某个字符,因此在Java语言中,这种方法实际上要比思路1时间复杂度更高一些。并不推荐使用,但是在C++中是可以的。下面给出C++和Java使用双指针解决这道题的代码。

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;
    }
};
public String replaceSpace(String s) {
    if(s == null || s.length() == 0){
        return s;
    }
    //扩充空间,空格数量2倍
    StringBuilder str = new StringBuilder();
    for (int i = 0; i < s.length(); i++) {
        if(s.charAt(i) == ' '){
            str.append("  ");
        }
    }
    //若是没有空格直接返回
    if(str.length() == 0){
        return s;
    }
    //有空格情况 定义两个指针
    int left = s.length() - 1;//左指针:指向原始字符串最后一个位置
    s += str.toString();
    int right = s.length()-1;//右指针:指向扩展字符串的最后一个位置
    char[] chars = s.toCharArray();
    while(left>=0){
        if(chars[left] == ' '){
            chars[right--] = '0';
            chars[right--] = '2';
            chars[right] = '%';
        }else{
            chars[right] = chars[left];
        }
        left--;
        right--;
    }
    return new String(chars);
}

4.Leetcode151 反转单词

给你一个字符串 s ,请你反转字符串中 单词 的顺序。

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

示例 1:
输入:s = "the sky is blue"
输出:"blue is sky the"
示例 2:
输入:s = "  hello world  "
输出:"world hello"
解释:反转后的字符串中不能存在前导空格和尾随空格。
示例 3:
输入:s = "a good   example"
输出:"example good a"
解释:如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。

解题思路1

  • 使用trim函数取出字符串开头和结尾的空格
  • 使用split分割单词,形成一个string[], 每一个元素是一个单词
  • 然后反转string[]数组即可。
public String reverseWords(String s) {
    // 如果一个字符串中有多个连续的空格
    // trim()的作用
    String[] strings = s.trim().split(" ");
    int left = 0, right = strings.length - 1;
    // 反转数组
    while (left < right) {
        String temp = strings[left];
        strings[left++] = strings[right];
        strings[right--] = temp;
    }
    // 构建字符串
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < strings.length; i++) {
        if ("".equals(strings[i]))
            continue;
        if (i == strings.length - 1) {
            sb.append(strings[i]);
            continue;
        }
        sb.append(strings[i] + " ");
    }
    return sb.toString();
}

这里需要特别注意的是,如果String str = " hello world ";,那么使用split(" ")之后的得到的数组是:

image-20230120174654062

所以需要在添加到StringBuilder中忽略掉这些空字符串。

第二个需要注意的是,如果想去除掉字符串开头和结尾的空格,可以使用str.trim()函数

解题思路2: 将字符串先整体反转一次,然后在每一个单词内部反转一次,就可以得到最终的结果。这个地方的难点是因为给的字符串可能在开头和结尾都包含若干个空格,以及每一个单词之间还有可能存在多个空格,所以需要删除掉字符串中额外的空格。

public String reverseWords(String s) {
    // 去掉字符串中额外的空格
    String removeSpaces = removeSpaces(s);
    // 整个字符串反转一次
    char[] chars = removeSpaces.toCharArray();
    reverse(chars, 0, chars.length - 1);
    // 每个单词内部反转
    int rec = 0; // 记录单词的左边界
    for (int i = 0; i <= chars.length; i++) {
        if (i == chars.length || chars[i] == ' ') {
            // 第一个单词遍历完毕
            reverse(chars, rec, i - 1);
            rec = i + 1;
        }
    }
    return new StringBuilder().append(chars).toString();
}

private String removeSpaces(String s) {
    char[] chars = s.toCharArray();
    int slow = 0;
    for (int fast = 0; fast < chars.length; fast++) {
        if (chars[fast] != ' ') {
            // 是单词
            // 判断slow 是不是在初始位置,
            // 如果不在初始位置,则需要在前面加空格
            if (slow != 0) {
                chars[slow++] = ' ';
            }
            // while循环将fast指向的单词添加到slow中
            // 只要chars[fast] != ' ' 那么说明fast一直指向的都是这个单词
            while (fast < chars.length && chars[fast] != ' ') {
                chars[slow++] = chars[fast++];
            }
        }
    }
    return new StringBuilder().append(chars, 0, slow).toString();
}

/**
     * 反转字符串
     * @param chars
     * @param start
     * @param end
     */
private void reverse(char[] chars, int start, int end) {
    while (start < end) {
        char temp = chars[start];
        chars[start++] = chars[end];
        chars[end--] = temp;
    }
}

image-20230120202653860

for (int i = 0; i < chars.length; i++) {
 if (chars[i] == ' ') {
     // 第一个单词遍历完毕
     reverse(chars, rec, i - 1);
     rec = i + 1;
 }
}

需要注意的是,在进行单词内部反转的时候,我们在条件上不能写上面的这种。判断只要有空格,那么就反转之间的单词。如果这样写,就会发现最后一个单词实际上没有反转。

原因是最后一个单词后面没有空格,但是也要反转。下面的这种写法才对。当执行到最后一个元素的时候,也要反转。

为什么是i<=chars.length,是因为要反转的区间是[rec, i - 1] 所以i必须执行到=chars.length

for (int i = 0; i <= chars.length; i++) {
 if (i == chars.length || chars[i] == ' ') {
     // 第一个单词遍历完毕
     reverse(chars, rec, i - 1);
     rec = i + 1;
 }
}

5.剑指Offer58 左旋转字符串

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。

示例 1:
输入: s = "abcdefg", k = 2
输出: "cdefgab"
示例 2:
输入: s = "lrloseumgh", k = 6
输出: "umghlrlose"

解题思路1: 进行两次字符串的反转即可

  • 首先将整个字符串进行反转
  • 然后再以n为界限,分割成两个子字符串,对这两个子字符串分别进行反转,得到最终结果。
public String reverseLeftWords(String s, int n) {
    // 先完全反转一次
    char[] chars = s.toCharArray();
    reverse(chars, 0, chars.length - 1);
    // 然后再左右分别反转一次
    reverse(chars, 0, chars.length - 1 - n);
    reverse(chars, chars.length - n, chars.length - 1);
    return new StringBuilder().append(chars).toString();
}
private void reverse(char[] chars, int start, int end) {
    while (start < end) {
        char temp = chars[start];
        chars[start++] = chars[end];
        chars[end--] = temp;
    }
}

图解如下:

image-20230120211411593

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

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

相关文章

Spring AOP 详解

Spring AOP 详解一、什么是 Spring AOP二、为何要用 AOP三、Spring AOP3.1 AOP 组成3.1.1 切面 (Aspect)3.1.2 连接点 (Join Point)3.1.3 切点 (Pointcut)3.1.4 通知 / 增强方法 (Advice)3.1.5 小结3.2 Spring AOP 使用3.2.1 添加 AOP 框架支持3.2.2 定义切面和切点3.2.3 定义相…

Python---字典相关知识

专栏&#xff1a;python 个人主页&#xff1a;HaiFan. 专栏简介&#xff1a;本专栏主要更新一些python的基础知识&#xff0c;也会实现一些小游戏和通讯录&#xff0c;学时管理系统之类的&#xff0c;有兴趣的朋友可以关注一下。 字典思维导图字典是什么创建字典查找键key字典的…

十分钟入门Zigbee

大部分教程通常都是已Zigbee原理开始讲解和学习&#xff0c;各种概念让初学者难以理解。本教程从一个小白的角度出发&#xff0c;入门无需任何Zigbee底层原理知识&#xff0c;只需要基本的MCU研发经验就可以掌握&#xff0c;让您快速实现zigbee组网和节点之间通信。 本教程采用…

JDBC快速入门,如何使用JDBC操作数据库?

文章目录1. 前言2. JDBC 概述2.1 概念2.2 优点3. JDBC 快速入门Java编程基础教程系列1. 前言 在 Java 开发中&#xff0c;使用 Java 语言操作数据库是非常重要的一部分&#xff0c;那么 Java 语言是如何操作数据库的呢&#xff1f;我们需要使用不同厂商的数据库时&#xff0c;…

23种设计模式(二十二)——访问者模式【行为变化】

文章目录 意图什么时候使用访问者真实世界类比访问者模式的实现访问者模式的优缺点亦称:Visitor 意图 封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于其内部各个元素的新操作。 什么时候使用访问者 1、如果你需要对一个复杂对象…

Redis脑裂为何会导致数据丢失?

1 案例 主从集群有1个主库、5个从库和3个哨兵实例&#xff0c;突然发现客户端发送的一些数据丢了&#xff0c;直接影响业务层数据可靠性。 最终排查发现是主从集群中的脑裂问题导致&#xff1a;主从集群中&#xff0c;同时有两个主节点都能接收写请求。 影响 客户端不知道应…

Python数模笔记-模拟退火算法(5)求解旅行商问题的联合算子模拟退火算法

Python数模笔记—求解旅行商问题的联合算子模拟退火算法&#xff08;完整例程&#xff09; 文章目录Python数模笔记—求解旅行商问题的联合算子模拟退火算法&#xff08;完整例程&#xff09;0 摘要1 引言2 模拟退火算法求解旅行商问题2.1 模拟退火算法2.2 多个新解的竞争机制2…

详解P431 塔防

题目说明gsy 最近在玩一个塔防游戏&#xff0c;但是这次她控制的是迷宫中的怪兽而非防御塔建造者游戏的地图是一个 n * m 的矩阵&#xff0c;起点在 (1,1) &#xff0c;终点在 (n,m) &#xff0c;gsy 每次可以选择上下左右四个方向移动 1 步这个地图上有很多的防御塔&#xff0…

“华为杯”研究生数学建模竞赛2005年-【华为杯】B题:空中加油问题的讨论(附获奖论文及C++代码)

赛题描述 对飞行中的飞机进行空中加油,可以大大提高飞机的直航能力。为了简化问题,便于讨论,我们作如下假设。 少辅机架数两种情况给出你的作战方案。 论文 一. 问题重述 空中加油技术可以大大提高飞机的直航能力。作战飞机称为主机,加油机称 为辅机。已知:( 1 )主…

[创业之路-50] :动态股权机制 -5- 创业公司股权分配常见的坑

1、 分工不清晰&#xff0c;决策不清晰&#xff0c;理念不一致分工必须要简单明晰初创公司的合伙人一般是三到五个&#xff0c;最合理的架构一开始最好是三个人&#xff0c;相互之间需要一段时间的磨合&#xff0c;了解清楚各自的特长&#xff0c;工作经历等等&#xff0c;不要…

微信小程序开发uni-app

一、uni-app简介官网&#xff1a;https://uniapp.dcloud.io/PC端&#xff1b;移动端&#xff1a;&#xff08;APP&#xff0c;WebApp&#xff09;&#xff1b;纯原生&#xff1a;&#xff08;IOS,Android &#xff09; 应用商店&#xff1b;H5Hybrid 模式&#xff08;混合&…

活动星投票最美农商人网络评选微信的投票方式线上免费投票

“最美农商人”网络评选投票_视频投票的相关评选_投票统计_微信不记名免费评选投票用户在使用微信投票的时候&#xff0c;需要功能齐全&#xff0c;又快捷方便的投票小程序。而“活动星投票”这款软件使用非常的方便&#xff0c;用户可以随时使用手机微信小程序获得线上投票服务…

树莓派Python虚拟环境、PyQt5、PySide2

要从头设置好一台可用于开发的树莓派&#xff0c;可以参考树莓派 4B 无屏幕&#xff0c;连接WiFi、SSH、VNC&#xff0c;系统换源、pip换源&#xff0c;安装中文输入法 Python虚拟环境 树莓派&#xff08;或者说arm平台&#xff09;使用Python虚拟环境的正确方式是使用pipenv…

【MyBatis】| 使⽤javassist⽣成类、面向接口的方式进行CRUD

目录 一&#xff1a;使⽤javassist⽣成类 1. Javassist的使⽤ 2. 动态生成类并实现接口 3. MyBatis中接⼝代理机制及使⽤ 二&#xff1a;面向接口的方式进行CRUD 一&#xff1a;使⽤javassist⽣成类 Javassist是⼀个开源的分析、编辑和创建Java字节码的类库。是由东京⼯业⼤…

SSH原理与运用

SSH原理与运用 SSH原理与运用&#xff08;一&#xff09;&#xff1a;远程登录 SSH原理与运用&#xff08;二&#xff09;&#xff1a;远程操作与端口转发 一. 什么是SSH&#xff1f; 简单说&#xff0c;SSH是一种网络协议&#xff0c;用于计算机之间的加密登录。需要指出的…

7个流行的强化学习算法及代码实现

目前流行的强化学习算法包括 Q-learning、SARSA、DDPG、A2C、PPO、DQN 和 TRPO。 这些算法已被用于在游戏、机器人和决策制定等各种应用中&#xff0c;并且这些流行的算法还在不断发展和改进&#xff0c;本文我们将对其做一个简单的介绍。 1、Q-learning Q-learning&#xff1…

23种设计模式(十九)——迭代器模式【数据结构】

文章目录 意图什么时候使用迭代器真实世界类比迭代器模式的实现迭代器模式的优缺点亦称:Iterator 意图 提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。 什么时候使用迭代器 1、当集合背后为复杂的数据结构, 且你希望对客户端隐藏其复杂性时 …

[QMT]05-获取基础行情信息

函数&#xff1a;获取合约基础信息get_instrument_detail(stock_code)1释义获取合约基础信息参数stock_code - string 合约代码返回 dict 数据字典&#xff0c;{ field1 : value1, field2 : value2, ... }&#xff0c;找不到指定合约时返回NoneExchangeID - string 合约市场代码…

零基础学JavaWeb开发(二十)之 spring框架(3)

SpringBean的AOP 1、AOP基本的概念 AOP(Aspect Oriented Programming)是一种面向切面的编程思想。面向切面编程是将程序抽象成各个切面&#xff0c;即解剖对象的内部&#xff0c;将那些影响了多个类的公共行为抽取到一个可重用模块里&#xff0c;减少系统的重复代码&#xff…

二叉树知识锦囊(三)

作者&#xff1a;爱塔居 专栏&#xff1a;数据结构​​​​​​ 作者简介&#xff1a;大三学生&#xff0c;希望和大家一起进步&#xff01; 目录 前言 1. 检查两棵树是否相同。 2. 另一颗树的子树。 3. 翻转二叉树。 4. 判断一颗二叉树是否是平衡二叉树。 5. 对称二叉树。 前…