首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【LeetCode刷题日记】:字符串替换技巧揭秘

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

作者头像
北极的代码
发布2026-04-22 13:52:52
发布2026-04-22 13:52:52
930
举报

前言:

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

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

给定一个字符串 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底层的字符串是不可变的,所以我们要转成字符数组进行处理。之后我们将这个转成字符数组拷贝到新的已经扩容的字符数组中,然后进行一系列的反转。

代码语言:javascript
复制
 char[] newS = new char[s.length() + count * 5];

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


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

整体演示,比较好理解

代码语言:javascript
复制
原字符串:   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"

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

题目答案:
代码语言:javascript
复制
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" 长,必须向后延伸,所以从后向前处理可以避免覆盖未处理的内容

第二种写法:

代码语言:javascript
复制
// 为了还原题目本意,先把原数组复制到扩展长度后的新数组,然后不再使用原数组、原地对新数组进行操作。
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

代码语言:javascript
复制
原长度 = 3
遇到数字'1' → len += 5 → len = 8
步骤2:创建新数组并复制
代码语言:javascript
复制
java

char[] ret = new char[8];  // [_, _, _, _, _, _, _, _]
// 复制原字符串
ret = ['a', '1', 'b', _, _, _, _, _]
        0    1    2    3  4  5  6  7
步骤3:从后向前填充
代码语言:javascript
复制
java

i = 2, j = 7

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

代码语言:javascript
复制
java

ret[7] = 'b'
j = 6

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

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

代码语言:javascript
复制
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' 不是数字

代码语言:javascript
复制
java

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

整体的逻辑更清晰易懂

  1. 逻辑清晰i 只管遍历原内容,j 只管填充新位置
  2. 容易理解:标准的双指针从后向前填充模式
  3. 没有歧义:不需要判断 j < i 这种边界条件
  4. 正确性保证:每个数字固定多占5个位置,指针移动步数确定

结语:

其实在写算法题的时候,我们要养成手撕的习惯,这对我们以后的面试帮助很大,刚开始肯定很难,有时候连方法的格式,返回值什么的都写的模糊不清,但只要坚持下来,会收获很大。 如果对你有帮助,请点赞,关注,收藏,你的支持就是我最大的鼓励!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-04-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目背景:卡码网 替换数字
    • 题目分析:
    • 接下来就是新数组中的处理了
    • 题目答案:
    • 总结
  • 第二种写法:
    • 流程:
    • 计算新数组长度
    • 步骤2:创建新数组并复制
    • 步骤3:从后向前填充
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档