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

替换数字(字符串算法)

替换数字

卡码网题目链接(opens new window)

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

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

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

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

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

样例输入:a1b2c3

样例输出:anumberbnumbercnumber

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

思路

如果想把这道题目做到极致,就不要只用额外的辅助空间了! (不过使用Java和Python刷题的录友,一定要使用辅助空间,因为Java和Python里的string不能修改)

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

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

如图:

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

有同学问了,为什么要从后向前填充,从前向后填充不行么?

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

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

这么做有两个好处:

  1. 不用申请新数组。
  2. 从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要将添加元素之后的所有元素向后移动的问题。
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);String s = sc.next();// 记录原始长度int originalLen = s.length();int newLen = originalLen;// 计算扩展后的总长度:每个数字替换为 "number"(多5个字符)for (int i = 0; i < originalLen; i++) {if (s.charAt(i) >= '0' && s.charAt(i) <= '9') {newLen += 5;}}// 创建结果字符数组char[] ret = new char[newLen];// 先将原字符串复制到结果数组前部for (int i = 0; i < originalLen; i++) {ret[i] = s.charAt(i);}// 从后往前处理:避免覆盖,实现原地扩展for (int i = originalLen - 1, j = newLen - 1; i >= 0; i--) {if (ret[i] >= '0' && ret[i] <= '9') {// 倒序填入 "number"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);}
}

一、时间复杂度:O(n)

其中 n 是输入字符串的原始长度。

分析:

步骤时间复杂度说明
第一次遍历(计算长度)O(n)遍历原字符串每个字符一次
复制原字符串到数组O(n)再次遍历原字符串
从后往前填充数组O(m)m 是最终数组长度,最坏情况是全是数字,m ≈ 6n → 仍是 O(n)

✅ 所有循环都是线性的,且最多遍历原字符串 2 次 + 结果数组 1 次。

虽然结果数组长度可能达到 6n,但它是输入长度的常数倍,所以:

总时间复杂度 = O(n + n + 6n) = O(n)


📊 二、空间复杂度:O(n)

其中 n 是输入字符串的原始长度。

分析:

空间占用项大小是否计入
char[] ret 数组newLen ≈ 最多 6n✅ 是主要空间开销
String sn✅ 输入本身,但通常不计入额外空间
其他变量(i, j, len 等)O(1)忽略

✅ 虽然 ret 数组最大可达 6n,但它是输入长度的 常数倍,所以:

空间复杂度 = O(n)

我看ai说可以改为这样(似乎确实比较可以)

换成这个后:

📊 一、时间复杂度:O(n)

其中 n 是输入字符串的原始长度。

分析:

步骤时间消耗
s.toCharArray()O(n) —— 创建一个长度为 n 的字符数组
for-each 循环O(n) —— 遍历每个字符一次
sb.append("number")每次调用是 O(6) = O(1)(常数时间)
sb.append(c)O(1)
sb.toString()O(m) —— m 是结果字符串总长度,最坏约 6n

总时间:

  • 循环执行 n 次
  • 每次操作是 O(1)(无论是 append 字符还是字符串)
  • 最后生成字符串是 O(m) ≈ O(6n) = O(n)

✅ 所以:

总时间复杂度 = O(n)

⚠️ 注意:虽然 append("number") 看似“操作6个字符”,但它内部是批量写入,时间是常数(与输入长度 n 无关),所以仍是 O(1) 操作。


📊 二、空间复杂度:O(n)

其中 n 是输入字符串的原始长度。

分析:

空间占用项大小是否计入
s.toCharArray()O(n)✅ 创建了新的 char[] 数组
StringBuilder 内部缓冲区O(m) ≈ O(6n)✅ 存储最终结果
最终 toString() 生成的字符串O(m) ≈ O(6n)✅ 输出字符串

关键点:

  • toCharArray() 会复制整个字符串 → 额外 O(n) 空间
  • StringBuilder 至少需要 O(m) ≈ O(n) 空间存储结果
  • 结果字符串最多是原长度的 6 倍(全是数字时)

✅ 所以:

总空间复杂度 = O(n + 6n) = O(n)

💡 虽然实际用了更多内存,但它是输入长度的常数倍,所以仍为 O(n)

http://www.dtcms.com/a/355166.html

相关文章:

  • 宋红康 JVM 笔记 Day08|堆
  • SMTPman,smtp协议是什么协议的核心功能!
  • 大数据毕业设计选题推荐-基于大数据的存量房网上签约月统计信息可视化分析系统-Hadoop-Spark-数据可视化-BigData
  • MySQL 8.0 事务深度解析:从核心特性到实战应用
  • 国产化Excel开发组件Spire.XLS教程:Python 将 CSV 转换为 Excel(.XLSX)
  • 【重磅发布】flutter_chen_updater-版本升级更新
  • 【开题答辩全过程】以 汽车售后管理系统的设计与实现为例,包含答辩的问题和答案
  • 首次创建Django项目初始化
  • Spring Boot 启动优化实战指南:从原理到落地的全链路性能调优
  • 我的6年!
  • Vue 组件循环 简单应用及使用要点
  • 算法加训 动态规划熟悉30题 ---下
  • 【ARM】MDK出现:Unable to find ARM libraries
  • ros2与gazebo harmonic机械臂仿真项目Moveit2YoloObb的优化
  • Linux 禁止 su 的几种限制手段:从 NoNewPrivileges 到 PAM 配置
  • Linux shell getopts 解析命令行参数
  • CRMEB小程序订阅消息配置完整教程(PHP版)附常见错误解决
  • 【论文阅读】PEPNet
  • 6.10 vue3 的nextclick
  • More Effective C++ 条款14:审慎使用异常规格(Exception Specifications)
  • 19、大数据处理系统分析与设计
  • [特殊字符] 监控体系里常见的角色
  • Python绝对引用与相对引用的核心差异
  • 架构评审:构建稳定、高效、可扩展的技术架构(下)
  • 深度学习篇---VGGNet网络结构
  • 阿里云轻量服务器的系统镜像和应用镜像的区别在哪?
  • 从零开始的python学习——浅谈python
  • 深度学习网络结构搭建
  • 【算法--链表题4】23.合并K个升序链表
  • Scikit-learn Python机器学习 - 什么是机器学习