当前位置: 首页 > news >正文

【LeetCode刷题日记】:字符串替换技巧揭秘

🔥个人主页:北极的代码(欢迎来访)
🎬作者简介:java后端学习者
❄️个人专栏:苍穹外卖日记,SSM框架深入,JavaWeb
命运的结局尽可永在,不屈的挑战却不可须臾或缺!

前言:

昨天是周六,本来是说每天更新两个文章,一篇算法相关的,一篇后端的,但是我虽然早上写了两题算法,下午出去了,然后晚上回来学了会项目再把文章发出来就已经凌晨了,所以就留到周末来发这个算法题目了,主要内容就是关于字符串的相关算法。

题目背景:卡码网 替换数字

给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。

例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"。

对于输入字符串 "a5b",函数应该将其转换为 "anumberb"

输入:一个字符串 s,s 仅包含小写字母和数字字符。

输出:打印一个新的字符串,其中每个数字字符都被替换为了number

样例输入:a1b2c3

样例输出:anumberbnumbercnumber

数据范围:1 <= s.length < 10000。

题目分析:

首先拿到这个题目,显然就是字符串反转的问题,但是又多了一些别的逻辑处理

首先扩充数组到每个数字字符替换成 "number" 之后的大小

例如 字符串 "a5b" 的长度为3,那么 将 数字字符变成字符串 "number" 之后的字符串为 "anumberb" 长度为 8。

然后从后向前替换数字字符,也就是双指针法,过程如下:i指向新长度的末尾,j指向旧长度的末尾。

为什么要从后向前填充,从前向后填充不行么?

从前向后填充就是O(n^2)的算法了,因为每次添加元素都要将添加元素之后的所有元素整体向后移动。

其实很多数组填充类的问题,其做法都是先预先给数组扩容带填充后的大小,然后在从后向前进行操作。

这里需要注意的是,我们用的是java,java底层的字符串是不可变的,所以我们要转成字符数组进行处理。之后我们将这个转成字符数组拷贝到新的已经扩容的字符数组中,然后进行一系列的反转。

char[] newS = new char[s.length() + count * 5];

关于这个count,也就是我们通过遍历得到字符串中有几个数字,从而count++,一个count对应五个位置。


接下来就是新数组中的处理了

整体演示,比较好理解

原字符串: a 1 b 索引: 0 1 2 新数组(初始): a 1 b _ _ _ _ _ 索引: 0 1 2 3 4 5 6 7 从后向前处理: 第1步: 复制'b' → b 索引: 7 第2步: 遇到'1' → 填入 number(反向) 填入: n u m b e r 索引: 1 2 3 4 5 6 最终结果: a n u m b e r b 0 1 2 3 4 5 6 7 转为字符串: "anumberb"

主要还是要判断哪个位置是数字,然后从后往前填充,至于为什么这样,因为如果是从前往后,每次添加元素都要将添加元素之后的所有元素整体向后移动。

题目答案:

import java.util.Scanner; public class Main { public static String replaceNumber(String s) { int count = 0; // 统计数字的个数 int sOldSize = s.length(); for (int i = 0; i < s.length(); i++) { if(Character.isDigit(s.charAt(i))){ count++; } } // 扩充字符串s的大小,也就是每个空格替换成"number"之后的大小 char[] newS = new char[s.length() + count * 5]; int sNewSize = newS.length; // 将旧字符串的内容填入新数组 System.arraycopy(s.toCharArray(), 0, newS, 0, sOldSize); // 从后先前将空格替换为"number" for (int i = sNewSize - 1, j = sOldSize - 1; j < i; j--, i--) { if (!Character.isDigit(newS[j])) { newS[i] = newS[j]; } else { newS[i] = 'r'; newS[i - 1] = 'e'; newS[i - 2] = 'b'; newS[i - 3] = 'm'; newS[i - 4] = 'u'; newS[i - 5] = 'n'; i -= 5; } } return new String(newS); }; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String s = scanner.next(); System.out.println(replaceNumber(s)); scanner.close(); } }

总结

这个算法的核心思路:

  1. 先创建足够大的新数组

  2. 复制原内容到新数组前半部分

  3. 从后向前处理:遇到非数字直接复制,遇到数字则从后往前写入 "number"

  4. 覆盖原数字位置:因为 "number" 比 "1" 长,必须向后延伸,所以从后向前处理可以避免覆盖未处理的内容


第二种写法:

// 为了还原题目本意,先把原数组复制到扩展长度后的新数组,然后不再使用原数组、原地对新数组进行操作。 import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String s = sc.next(); int len = s.length(); for (int i = 0; i < s.length(); i++) { if (s.charAt(i) >= 0 && s.charAt(i) <= '9') { len += 5; } } char[] ret = new char[len]; for (int i = 0; i < s.length(); i++) { ret[i] = s.charAt(i); } for (int i = s.length() - 1, j = len - 1; i >= 0; i--) { if ('0' <= ret[i] && ret[i] <= '9') { ret[j--] = 'r'; ret[j--] = 'e'; ret[j--] = 'b'; ret[j--] = 'm'; ret[j--] = 'u'; ret[j--] = 'n'; } else { ret[j--] = ret[i]; } } System.out.println(ret); }

流程:

计算新数组长度

text

原长度 = 3 遇到数字'1' → len += 5 → len = 8

步骤2:创建新数组并复制

java char[] ret = new char[8]; // [_, _, _, _, _, _, _, _] // 复制原字符串 ret = ['a', '1', 'b', _, _, _, _, _] 0 1 2 3 4 5 6 7

步骤3:从后向前填充

java i = 2, j = 7

第1次循环 (i=2)ret[2] = 'b'不是数字

java ret[7] = 'b' j = 6

结果:[a, 1, b, _, _, _, _, b]

第2次循环 (i=1)ret[1] = '1'是数字

java ret[6] = 'r' // j=6→5 ret[5] = 'e' // j=5→4 ret[4] = 'b' // j=4→3 ret[3] = 'm' // j=3→2 ret[2] = 'u' // j=2→1 ret[1] = 'n' // j=1→0

结果:[a, n, u, m, b, e, r, b]

第3次循环 (i=0)ret[0] = 'a'不是数字

java ret[0] = 'a' // j=0→ -1

整体的逻辑更清晰易懂

  1. 逻辑清晰i只管遍历原内容,j只管填充新位置

  2. 容易理解:标准的双指针从后向前填充模式

  3. 没有歧义:不需要判断j < i这种边界条件

  4. 正确性保证:每个数字固定多占5个位置,指针移动步数确定


结语:

其实在写算法题的时候,我们要养成手撕的习惯,这对我们以后的面试帮助很大,刚开始肯定很难,有时候连方法的格式,返回值什么的都写的模糊不清,但只要坚持下来,会收获很大。

如果对你有帮助,请点赞,关注,收藏,你的支持就是我最大的鼓励!

http://www.jsqmd.com/news/668546/

相关文章:

  • SCTransform vs 传统方法:单细胞亚群分析中的标准化选择与性能对比
  • 天赐范式第16天:【硬核物理】哥本哈根学派沉默了:用纯经典混沌模拟出量子双缝干涉,量子力学统计特性可能是高维相空间混沌投影的观点(附源码)
  • 专业的东莞高新技术企业认定资质办理公司
  • FPGA实战:手把手教你用CORDIC Translate IP核搞定复数转极坐标(附定点数归一化避坑指南)
  • F460低功耗模式实战:睡眠/停止/掉电模式下的PVD配置避坑指南
  • golang如何实现错误预算Error Budget计算_golang错误预算Error Budget计算实现实战
  • 终极指南:OpenCore Legacy Patcher让老旧Mac焕发新生的3大核心操作
  • 基于多目标遗传NSGA-II算法的水火光系统多目标优化调度研究(Matlab代码实现)
  • 专业级硬件控制终极指南:Lenovo Legion Toolkit深度定制与性能优化
  • SQL分组统计时如何处理文本类型聚合_GROUP_CONCAT的用法
  • 基于Voronoi自适应分区的Qlearning强化学习粒子群算法的海上风电场电气系统拓扑优化研究(Matlab代码实现)
  • 记录VSCode开发C#常用插件
  • 罗茨风机选型推荐指南:用过回转鼓风机的人给我推荐口碑品牌好的
  • Day03 完整学习计划 | 阿里云ACP大模型解决方案专家
  • 从零到一:PrimeTime静态时序分析入门指南
  • 为什么DeepMind、OpenAI、清华交叉信息院都在抢建“证明优先”AGI架构?——2026奇点大会核心议程深度泄露(含3份签署NDA的架构图)
  • 2026年4月浙江企业采购指南:实力激光笔品牌深度测评与推荐 - 2026年企业推荐榜
  • 前瞻2026:江阴市爱维叶幼儿园(托育服务一体化)如何定义下一代托育标准? - 2026年企业推荐榜
  • 基于NSGA-2算法的水火光系统多目标优化调度研究(Matlab代码实现)
  • 如何快速上手Fiji:科学图像分析的终极完整指南
  • 别再折腾软路由了!用OpenWrt 23.05 + Docker Compose,5分钟搞定青龙面板全家桶
  • 从Altium Designer转KiCad 7.0:一个硬件工程师的实战避坑与效率提升指南
  • 2026年4月更新:固体过氧化氢服务商深度解析,为何濮阳圣恺被行业巨头青睐? - 2026年企业推荐榜
  • 【AI Agent实战】我让AI分析了自己3个月的写作风格,发现了5个致命盲区
  • RevokeMsgPatcher 2.1:Windows平台防撤回终极解决方案完全指南
  • 极客卸载工具深度解析:6.69MB的绿色卸载神器为何备受推崇
  • AI Agent 开发指南
  • Agent 智能体:核心概念、技术架构与实战搭建全解
  • ComfyUI-AnimateDiff-Evolved:深度解析动画生成的技术架构与优化实践
  • Windows卸载工具横向对比:极客卸载为何能脱颖而出