【感悟《剑指offer》典型编程题的极练之路】02字符串篇!
个人主页:秋风起,再归来~
文章所属专栏:《剑指offer》典型编程题的极练之路
个人格言:悟已往之不谏,知来者犹可追
克心守己,律己则安!
目录
一、C/C++中字符数组与字符常量
二、面试题(替换空格)
2.1时间复杂度为 Q(㎡)的解法,不足以拿到 Offer
2.2 创建新的数组解题
2.3时间与空间复杂度分别为O(N)和O(1)的算法!(搞定offer就靠它了!)
编辑
三. 完结散花
一、C/C++中字符数组与字符常量
为了节省空间,C/C++把常量字符串放到单独的一个内存区域。当几个指针赋值给相同的常量字符串时,它们实际上会指向相同的内存地址。但用常量内存初始化数组,情况却有所不同。下面通过一个面试题来学习这一知识点。
#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>int main()
{char* s1 = "abcdef";char* s2 = "abcdef";char* s3[] = { "abcdef" };char* s4[] = { "abcdef" };if (s1 == s2){printf("s1与s2相等\n");}else{printf("s1与s2不相等\n");}if (s3 == s4){printf("s3与s4相等\n");}else{printf("s3与s4不相等\n");}return 0;
}
如果我们运行下面代码的话结果是什么呢?

为什么呢?
我们先通过调试来理解一下?

我们可以看到s1和s2的值相等,说明它们指向了同一块内存地址!
反之,s3与s4所指向的空间则是不同的!

那这又是为什么呢?
首先我们知道常量是不能被改变的,当内存中开辟了一片空间存放一个字符串常量并且有一个指针指向它,有朝一日,我们不小心又创建了一个相同的常量字符串并且用另一个指针指向它,这时内存并不会再创建一片空间来存放这个常量字符串,而是直接让另一个指针指向向前开辟的空间。
那为什么字符数组却不同呢,那是因为字符数组是可修改的,如果它们指向同一块空间,有朝一日,我想修改这个字符数组,那另一个字符数组必然也会被修改!
二、面试题(替换空格)
描述:
请实现一个函数,将一个字符串s中的每个空格替换成“%20”。
例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
数据范围:0≤en(s)≤1000 。保证字符串中的字符为大写英文字母、小写英文字母和空格中的一种。
题目链接:点击进入
在网络编程中,如果URL参数中含有特殊字符,如空格“#”等,则可能导致服务器端无法获得正确的参数值。我们需要将这些特殊符号转换成服务器可识别的字符。转换的规则是在%后面跟上ASCLL码的两位十六进制的表示。比如空格的ASCLL码是32即十六进制的0x20,因此空格被替换为%20,再比如#的ASCLL为35,即十六进制的0x23,他在URL中被替换为%23。
看到这个题目,我们首先应该想到的是原来一个空格字符,替换之后变成"%、"2和0这3个字符,因此字符串会变长。如果是在原来的字符串上进行替换,就有可能覆盖修改在该字符串后面的内存。如果是创建新的字符串并在新的字符串上进行替换,那么我们可以自己分配足够多的内存。由于有两种不同的解决方案,我们应该向面试官问清楚,让他明确告诉我们他的需求。假设面试官让我们在原来的字符串上进行替换,并且保证输入的字符串后面有足够多的空余内存。
2.1时间复杂度为 Q(㎡)的解法,不足以拿到 Offer
现在我们考虑怎么执行替换操作。最直观的做法是从头到尾扫描字符每次碰到空格字符的时候进行替换。由于是把1个字符替换成3个字串,符,我们必须要把空格后面所有的字符都后移2字节,否则就有两个字符被覆盖了。
举个例子,我们从头到尾把"We are happy,"中的每个空格替换成"%20"。为了形象起见,我们可以用一个表格来表示字符串,表格中的每个格子表示一个字符,如图 所示。

注:(a)字符串"Weare happy."。(b)把字符串中的第一个空格替换成"%20”。黄色背景表示需要移动的字符。(c)把字符串中的第二个空格替换成”%20"。黄色背景表示需要移动一次的字符,红色色背景表示需要移动两次的字符。
我们替换第一个空格,这个字符串变成图(b)中的内容,表格中黄色背景的格子表示需要进行移动的区域。接着我们替换第二个空格,替换之后的内容如图2.3(c)所示。同时,我们注意到用红色背景标注的happy”部分被移动了两次。
假设字符串的长度是n。对每个空格字符,需要移动后面O(n)个字符:因此对于含有 0(n)个空格字符的字符串而言,总的时间效率是 O(n’)。
当我们把这种思路阐述给面试官后,他不会就此满意,他将让我们寻找更快的方法。在前面的分析中,我们发现数组中很多字符都移动了很多次,能不能减少移动次数呢?答案是肯定的。我们换一种思路,把从前向后替换改成从后向前替换。
2.2 创建新的数组解题
结合代码注释和图解就很容易理解这种算法了~

char* replaceSpace(char* s ) {// write code hereif(s==NULL)return NULL;//先记录与字符串的大小int len=strlen(s);//记录空格的数量int count=0;int i=0;while(s[i]!='\0'){if(s[i]==' ')count++;i++;}//创建一个新的字符数组char* newStr=(char*)malloc(sizeof(char)*(len+count*2));//将原字符串的内容拷贝进新的字符数组,遇到空格就替换int j=0;int end=0;while(s[end]!='\0'){if(s[end]==' '){newStr[j++]='%';newStr[j++]='2';newStr[j++]='0';}else{newStr[j++]=s[end];}end++;}return newStr;
}
2.3时间与空间复杂度分别为O(N)和O(1)的算法!(搞定offer就靠它了!)

char* replaceSpace(char* s ) {// write code hereint end=0;if(s==NULL)return NULL;int count=0;//记录空格的数量while(s[end]!='\0')//找到字符串的末尾{if(s[end]==' '){count++;}end++;}//找到替换过后字符串的末尾int newEnd=end+2*count;//从后往前移动字符并且替换空格while(end>=0&&end<newEnd){if(s[end]==' '){s[newEnd--]='0';s[newEnd--]='2';s[newEnd--]='%';}else{s[newEnd--]=s[end];}end--;}return s;
}
这个算法的核心在于如何高效地将字符串中的空格替换为"%20",同时保证不覆盖或遗漏任何字符。算法的原理可以概括为以下几个步骤:
步骤一:计算空格数量
首先,我们需要遍历一遍输入的字符串,统计其中空格的数量。这是因为每个空格都将被替换为三个字符('%'、'2' 和 '0'),所以我们需要知道有多少个空格,以便计算替换后字符串的总长度。
步骤二:计算新字符串长度
接下来,我们根据原始字符串的长度和空格的数量,计算出替换后字符串的总长度。由于每个空格替换为三个字符,所以新字符串的长度将是原始长度加上空格数量乘以2(因为每个空格增加了两个字符)。
步骤三:从后向前遍历并替换
然后,我们从字符串的末尾开始,向前遍历原始字符串。这样做的目的是为了避免在替换过程中覆盖还未处理的字符。对于每个字符,我们检查它是否是空格。如果是空格,我们就将其替换为"%20",并更新新字符串的索引位置。如果不是空格,我们则直接将字符复制到新字符串的对应位置,并更新索引。
这个算法的关键在于利用了字符串的末尾空间,从后向前进行替换操作,避免了额外的内存分配和字符串拷贝。它只需要一次遍历就能完成替换操作,时间复杂度是O(n),其中n是字符串的长度。因此,这个算法是高效且实用的。
此外,值得注意的是,这个算法直接修改了输入的字符串,而不是创建了一个新的字符串。这意味着在调用这个函数之后,原始的字符串已经被修改。如果原始字符串不应该被修改,那么在调用这个函数之前,你需要先复制一份原始字符串。
注:这个算法假设输入的字符串有足够的空间来容纳替换后的结果。如果原始字符串的空间不足以容纳替换后的结果,那么这个算法可能会导致缓冲区溢出。因此,在实际使用时,你需要确保输入的字符串有足够的空间,或者在调用这个函数之前,先分配一个足够大的新字符串来存放替换后的结果。
值得一提的是:这种算法在牛客上并不能通过全部的测试用例,我估计是后台调用函数时传递的字符数组并没有足够大的空间,导致数组越界访问了~
一些感悟:在面试的过程中,我们也可以和前面的分析一样画一两个示意图解释自己的思路,这样既可以帮助我们厘清思路,也可以使我们和面试官交流更加的高效!
三. 完结散花
好了,这期的分享到这里就结束了~
如果这篇博客对你有帮助的话,可以用你们的小手指点一个免费的赞并收藏起来哟~
如果期待博主下期内容的话,可以点点关注,避免找不到我了呢~
我们下期不见不散~~


相关文章:
【感悟《剑指offer》典型编程题的极练之路】02字符串篇!
个人主页:秋风起,再归来~ 文章所属专栏:《剑指offer》典型编程题的极练之路 个人格言:悟已往之不谏,知来者犹可追 克心守己,…...
通过 Docker 实现国产数据库 OpenGauss 开发环境搭建
通过 Docker 实现国产数据库 OpenGauss 开发环境搭建 一 前置准备 2.1 下载镜像 docker pull enmotech/opengauss:5.0.1构建镜像的 Dockerfile,方便后期实现个性化定制: FROM ubuntu:22.04 as builderARG TARGETARCHWORKDIR /warehouseRUN set -eux;…...
【Java】LinkedList模拟实现
目录 整体框架IMyLinkedList接口IndexNotLegalException异常类MyLinkedList类成员变量(节点信息)addFirst(头插)addLast(尾插)在指定位置插入数据判断是否存在移除第一个相等的节点移除所有相等的节点链表的长度打印链表释放回收链表 整体框架 IMyLinkedList接口 这个接口用来…...
ubuntu下mysql常用命令
1. 登录数据库 mysql -u root -p 2.创建数据库 create database 数据库名字 mysql> create database yourdb; Query OK, 1 row affected (0.03 sec)3.显示数据库 show databases; 实操结果如下 mysql> show databases; -------------------- | Database | ---…...
燃气官网安全运行监测系统-阀井燃气监测仪-旭华智能
近年来,燃气爆炸事故频发,造成了重大人员伤亡和财产损失。这也再次为我们敲响警钟,燃气是我们日常生活中不可或缺的能源,但其潜在的危险性也是不容小觑。因此在重要节点加装燃气阀井气体监测仪,并将数据上传到系统平台…...
vue 文件预览(docx、.xlsx、pdf)
1.ifream <iframe src"" ></iframe> 注: src里面是文件地址 2.vue-office 支持vue2和vue3提供docx、.xlsx、pdf多种文档的在线预览方案 2.1安装 #docx文档预览组件 npm install vue-office/docx vue-demi#excel文档预览组件 npm install vue-office…...
云架构(二) 大使模式
Ambassador pattern (https://learn.microsoft.com/en-us/azure/architecture/patterns/ambassador) 简单描述 创建一个助手服务,这个服务代表消费服务或者应用程序发送网络请求。大使服务可以看做是与客户机同一个位置的进程外代理。 这种…...
.NET Path类库的特殊方法
在.NET中Path类库是非常常用的一个类库,包含很多我们常用的方法,常用的方法这里就不详细说明了,这里记录下几个非常规的方法。 获取随机文件名: //将返回随机的文件名Console.WriteLine(Path.GetRandomFileName()); 获取禁止在路…...
【JVM】JVM常用性能调优参数详细介绍
JVM常用性能调优参数详细介绍 一、何时进行JVM调优二、性能调优三、JVM调优的基本原则四、JVM调优目标五、JVM调优的步骤六、JVM参数七、JVM参数解析及调优八、JVM参数使用手册8.1 内存相关8.2 GC策略相关8.3 GC日志相关8.4 异常相关8.5 问题定位及优化相关九、参考文档一、何时…...
React中的受控组件与非受控组件
受控组件与非受控组件 受控组件 组件(input, select)的状态与state的值绑定,组件的状态全程响应外部数据 class TestComponent extends React.Component {constructor (props) {super(props);this.state { username: lindaidai };}render () {return <input …...
uniapp实现u-datetime-picker时间选择器的默认日期定位,解决default-value不生效问题
uniapp实现u-datetime-picker,设置默认定位日期,解决default-value不生效问题 想实现的效果是点开时间选择器默认显示当前日期,而不是该选择器最早的日期 给选择器添加ref属性,如下: <u-datetime-picker :show&q…...
react native 使用ScrollView实现下拉更新,上拉加载更多
在React Native中,要实现下拉更新和上拉加载更多的功能,你需要自定义ScrollView组件,监听滚动事件并根据滚动的位置来判断何时触发更新和加载更多的操作。以下是一个基本的实现思路: 监听滚动事件:使用ScrollView的on…...
vue2完结
笔记 关于不同版本的Vue: 1.vue.js与vue.runtime.xxx.js的区别:(1)vue.js是完整版的Vue,包含:核心功能模板解析器(2)vue.runtime.xxx.js是运行版本的Vue,只包含核心功能,没有模板解析器 2.因为…...
前端网页之间传递参数
在多页面应用中,我们可能面临着前端页面之间传递参数的情况,在一个页面获取到一些参数信息后,到另一个页面去进行后续处理,需要将前一个页面得到的一些参数带到第二个页面。当参数较少时,可以在跳转第二个页面时通过se…...
【常见面试题】Golang中,协程数最多可以开多少个?
参考: Goroutine 究竟可以开多少? 一、先说结论: 能开多少个协程,取决于单个协程处理方法所占用的CPU和内存资源(也就是看你计算机运行的应用程序的具体代码逻辑)。 二、具体来说: 如果是C…...
RabbitMQ基础笔记
视频链接:【黑马程序员RabbitMQ入门到实战教程】 文章目录 1.初识MQ1.1.同步调用1.2.异步调用1.3.技术选型 2.RabbitMQ2.1.安装2.1.1 Docker2.1.1 Linux2.1.1 Windows 2.2.收发消息2.2.1.交换机2.2.2.队列2.2.3.绑定关系2.2.4.发送消息 2.3.数据隔离2.3.1.用户管理2…...
大型项目管理神器:掌握yarn monorepo的安装和使用
I. 引言 在当今的前端开发中,由于项目规模的不断增长和多团队协同,Monorepo成为了越来越流行的开发模式。Monorepo指的是将多个相关项目或者模块打包在一起的软件开发模式,它可以让开发人员更好地组织管理代码,减少重复的代码&am…...
算法打卡day28|贪心算法篇02|Leetcode 122.买卖股票的最佳时机 II、55. 跳跃游戏、45.跳跃游戏 II
算法题 Leetcode 122.买卖股票的最佳时机 II 题目链接:122.买卖股票的最佳时机 II 大佬视频讲解:买卖股票的最佳时机 II视频讲解 个人思路 因为只有一只股票,且两天作一个交易单元,那每次只收集正利润就可以最终最多可以获取的利润…...
2013年认证杯SPSSPRO杯数学建模A题(第一阶段)护岸框架全过程文档及程序
2013年认证杯SPSSPRO杯数学建模 A题 护岸框架 原题再现: 在江河中,堤岸、江心洲的迎水区域被水流长期冲刷侵蚀。在河道整治工程中,需要在受侵蚀严重的部位设置一些人工设施,以减弱水流的冲刷,促进该处泥沙的淤积&…...
【3】3道链表力扣题:删除链表中的节点、反转链表、判断一个链表是否有环
3道链表力扣题 一、删除链表中的节点🌏 题目链接📕 示例🍀 分析💻 代码 二、反转链表🌏 题目链接📕 示例🍀 分析① 递归② 迭代 三、判断一个链表是否有环🌏 题目链接📕 …...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
破解路内监管盲区:免布线低位视频桩重塑停车管理新标准
城市路内停车管理常因行道树遮挡、高位设备盲区等问题,导致车牌识别率低、逃费率高,传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法,正成为破局关键。该设备安装于车位侧方0.5-0.7米高度,直接规避树枝遮…...
零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...



