《剑指Offer》--替换空格

本文介绍了一种在原地将字符串中的空格替换为%20的方法,避免使用额外空间。通过两次遍历,先计算空格数量并确定新字符串长度,再从后向前逐个替换,确保效率为O(n)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

请实现一个函数,把字符串中的空格替换成%20,例如,输入“we are happy.”,输出“we%20are%20happy.”

将长度为1的空格替换为长度为3的“%20”,字符差的产度变长。如果允许我们开辟一个新的数组来存放替换空格后的字符串,那么这道题目就非常简 单。设置两个指针分别指向新旧字符串首元素,遍历原字符串,如果碰到空格就在新字符串上填入“%20”,否则就复制元字符串上的内容。
如果面试官要求只能在原先的字符串上操作,并且字符数组足够长以保存后替换后的字符,那么就得从别的方面着手。

方法一:
从前向后遍历,遇到空格就替换为%20,考虑可能会覆盖掉后面的字符,假设字符长度为n,每替换一个空格,就会需要向后移动O(n)个字符,因此就含有n个空格的字符串而言,总的时间效率是O(n^2)。这种方法显然不优。
方法二:
那我们换一种角度,从后先前遍历搜索,我们可以先遍历一遍数组,计算出空格的总数,并且可以由此计算出替换之后的字符串总长度,每替换一个空格,长度增加2,那么替换后的字符串总长度就等于原来的字符串长度加上2乘以空格数。

  1. 遍历求出空格数和字符串长度
  2. 求出替换后的字符串长度(原长+2*空格数)
  3. 设置两个指针p1,p2,分别指向原始字符串末尾和替换之后的字符串末尾
  4. 如果p1指向内容不为空格,那么将内容赋值给p2指向的位置,如果p1指向为空格,那么从p2开始赋值“02%”
  5. 直到p1==p2时表明字符串中的所有空格都已经替换完毕。

    代码如下:

//把字数数组中的空格替换成%20
    void replaceBlank(char s[],int len) {
        //判断空指针,参数异常
        if(s==null || len <= 0){ 
            return ;
        }
        int i = 0;
        int originalLen = 0;
        int newLen = 0;
        int blankCount = 0;
        while(s[i]!='\0') {
            originalLen ++;
            if(s[i]==' ') {
                ++blankCount;
            }
            ++i;
        }
        newLen = originalLen + 2*blankCount;
        //如果新的长度大于了数组长度就会越界
        if(newLen > len) 
            return ;
        int indexOfOriginal = originalLen;//指向新数组的最后一个位置
        int indexOfNew = newLen;//指向原数组的最后一个位置
        while(indexOfOriginal >=0 && indexOfNew > indexOfOriginal) {
            if(s[indexOfOriginal]== ' ') {
                s[indexOfNew--] = '0';
                s[indexOfNew--] = '2';
                s[indexOfNew--] = '%';
            }else {
                s[indexOfNew--] = s[indexOfOriginal];
            }
            --indexOfOriginal;
        }
    }
    @Test
    public void testReplaceBlank() {
        char s[] = {'w','e',' ','a','r','e',' ','h','a','p','p','y','\0',' ',' ',' ',' ',' '};
        replaceBlank(s,18);
        System.out.println(s);
    }

输出结果:

we%20are%20happy

传字符串

public String replaceSpace(StringBuffer str) {
        int len  =  str.length();
        int blankNum = 0;
        for(int i=0;i<len;i++) {
            if(str.charAt(i)==' ') blankNum++;
        }
        for(int i=0;i<blankNum*2;i++) {
            str.append(' ');
        }
        char a[] = str.toString().toCharArray();
        int newLen = len+blankNum*2;
        int indexOld = len - 1;
        int indexNew  = newLen - 1;
        while(indexOld>=0 && indexOld<indexNew) {
            if(a[indexOld]!=' ') {
                a[indexNew--] = a[indexOld];
            }else {
                a[indexNew--] = '0';
                a[indexNew--] = '2';
                a[indexNew--] = '%';
            }
            indexOld--;
        } 
        StringBuilder sb = new StringBuilder();
        for(char c:a) 
            sb.append(c);
        return sb.toString();
    }

备注:(c++代码)

#include<iostream>
using namespace std;
//把字数数组中的空格替换成%20
    void replaceBlank(char s[],int len) {
        //判断空指针,参数异常
        if(s==NULL || len <= 0){ 
            return ;
        }
        int i = 0;
        int originalLen = 0;
        int newLen = 0;
        int blankCount = 0;
        while(s[i]!='\0') {
            originalLen ++;
            if(s[i]==' ') {
                blankCount++;
            }
            i++;
        }
        newLen = originalLen + 2*blankCount;
        int indexOfOriginal = originalLen;//指向新数组的最后一个位置
        int indexOfNew = newLen;//指向原数组的最后一个位置
        while(indexOfOriginal >=0 && indexOfNew > indexOfOriginal) {
            if(s[indexOfOriginal]== ' ') {
                s[indexOfNew--] = '0';
                s[indexOfNew--] = '2';
                s[indexOfNew--] = '%';
            }else {
                s[indexOfNew--] = s[indexOfOriginal];
            }
            indexOfOriginal--;
        }
    }
    void main() {
        //char s[] = {'w','e',' ','a','r','e',' ','h','a','p','p','y'};
        char s[20] = "we are happy." ;
        replaceBlank(s,12);
        cout<<s;
    }

相关问题:

`有两个排序的数组A1和A2,内存在A1的末尾有足够的空间容纳A2,请实现一个函数,把A2中的所有数字插入到A1中,并保持有序。`

解法:和前面一样,很多人首先想到的办法是在A1中从头到尾复制数字,这样出现多次复制同一个数字的情况。更好的办法是从尾到头比较A1和A2的数字,并把较大的数字复制到A1中合适的位置。

代码:

#include<iostream>
using namespace std;

void a1_a2(int a1[],int a2[],int a1_len) {
    if(a1==NULL || a2==NULL || a1_len <=0)
        return ;
    int i = 0;
    int len1=0,len2=0;
    //遍历连个数组,求出字符长度
    while(a1[i]!='\0'){
        len1++;
        i++;
    }
    i = 0;
    while(a2[i]!='\0'){
        len2++;
        i++;
    }
    int newLen = len1 + len2;
    if(newLen > a1_len) {
        //越界
        return;
    }
    int indexOfNew = newLen - 1;
    int indexOfA1 = len1-1;
    int indexOfA2 = len2-1;
    while(indexOfA1>=0 && indexOfA2>=0) {
        if(a1[indexOfA1] <= a2[indexOfA2]) 
            a1[indexOfNew--] = a2[indexOfA2--];
        else 
            a1[indexOfNew--] = a1[indexOfA1--];
    }
    while(indexOfA1 >= 0) {
        a1[indexOfNew--] = a1[indexOfA1--];
    }
    while(indexOfA2 >= 0) {
        a1[indexOfNew--] = a2[indexOfA2--];
    }
} 

void main(){
    int a1[10] = {3,5,8,9};
    int a2[7] = {2,6,7,10};
    a1_a2(a1,a2,10);
    int i = 0;
    while(a1[i]!='\0') {
        cout<<a1[i];
        i++;
    }
   cout<<endl;

}
电动汽车数据集:2025年3K+记录 真实电动汽车数据:特斯拉、宝马、日产车型,含2025年电池规格和销售数据 关于数据集 电动汽车数据集 这个合成数据集包含许多品牌和年份的电动汽车和插电式车型的记录,捕捉技术规格、性能、定价、制造来源、销售和安全相关属性。每一行代表由vehicle_ID标识的唯一车辆列表。 关键特性 覆盖范围:全球制造商和车型组合,包括纯电动汽车和插电式混合动力汽车。 范围:电池化学成分、容量、续航里程、充电标准和速度、价格、产地、自主水平、排放、安全等级、销售和保修。 时间跨度:模型跨度多年(包括传统和即将推出的)。 数据质量说明: 某些行可能缺少某些字段(空白)。 几个分类字段包含不同的、特定于供应商的值(例如,Charging_Type、Battery_Type)。 各列中的单位混合在一起;注意kWh、km、hr、USD、g/km和额定值。 列 列类型描述示例 Vehicle_ID整数每个车辆记录的唯一标识符。1 制造商分类汽车品牌或OEM。特斯拉 型号类别特定型号名称/变体。型号Y 与记录关联的年份整数模型。2024 电池_类型分类使用的电池化学/技术。磷酸铁锂 Battery_Capacity_kWh浮充电池标称容量,单位为千瓦时。75.0 Range_km整数表示充满电后的行驶里程(公里)。505 充电类型主要充电接口或功能。CCS、NACS、CHAdeMO、DCFC、V2G、V2H、V2L Charge_Time_hr浮动充电的大致时间(小时),上下文因充电方法而异。7.5 价格_USD浮动参考车辆价格(美元).85000.00 颜色类别主要外观颜色或饰面。午夜黑 制造国_制造类别车辆制造/组装的国家。美国 Autonomous_Level浮点自动化能力级别(例如0-5),可能包括子级别的小
内容概要:本文详细介绍了IEEE论文《Predefined-Time Sensorless Admittance Tracking Control for Teleoperation Systems With Error Constraint and Personalized Compliant Performance》的复现与分析。论文提出了一种预定义时间的无传感器导纳跟踪控制方案,适用于存在模型不确定性的遥操作系统。该方案通过具有可调刚度参数的导纳结构和预定义时间观测器(PTO),结合非奇异预定义时间终端滑模流形和预定义时间性能函数,实现了快速准确的导纳轨迹跟踪,并确保误差约束。文中详细展示了系统参数定义、EMG信号处理、预定义时间观测器、预定义时间控制器、可调刚度导纳模型及主仿真系统的代码实现。此外,还增加了动态刚度调节器、改进的广义动量观测器和安全约束模块,以增强系统的鲁棒性和安全性。 适合人群:具备一定自动化控制理论基础和编程能力的研究人员、工程师,尤其是从事机器人遥操作、人机交互等领域工作的专业人士。 使用场景及目标:①理解预定义时间控制理论及其在遥操作系统中的应用;②掌握无传感器力观测技术,减少系统复杂度;③学习如何利用肌电信号实现个性化顺应性能调整;④探索如何在保证误差约束的前提下提高系统的响应速度和精度。 阅读建议:本文内容涉及较多的数学推导和技术细节,建议读者先熟悉基本的控制理论和Python编程,重点理解各个模块的功能和相互关系。同时,可以通过运行提供的代码示例,加深对理论概念的理解,并根据自身需求调整参数进行实验验证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值