个人评价:又是一道内置函数 5s 解题(迷惑脸?)但是个人认为还是蛮值得深入的
题目难度:🌟 (参考 LeeCode 简单🌟 、中等🌟 🌟 、困难🌟 🌟 🌟 )
另,通常算法题会考察分析时间复杂度和空间复杂度,可参考笔者之前的文章
替换空格
题目描述
请实现一个函数,把字符串 s 中的每个空格替换成”%20”。
示例 1:
输入:s = “We are happy.”
输出:“We%20are%20happy.”
限制:
0 <= s 的长度 <= 10000
解题思路
方法一
replace 函数不少语言应该都支持吧?或者正则匹配也成
不管了,直接上 😂
func replaceSpace(s string) string {
return strings.ReplaceAll(s, " ", "%20")
}
方法二
好吧,好歹也是算法的题目,想想遍历实现以及这题的初衷?
字符串通常被设计成「不可变」的类型(Go、Python、Java),即无法直接修改字符串的某一位字符,需要新建一个字符串实现。
那么,我们通常会处理为:
- 初始化一个 list
- 遍历列表 s 中的每个字符 c
- 当 c 为空格时:向 list 后添加字符串 “%20”
- 当 c 不为空格时:向 list 后添加字符 c
- 将列表 list 转化为字符串并返回
复杂度?🙌 时间&空间均为 O(n)
C++ 中,字符串可变,参考先扩展后填充的方式,示例图如下:
题目引申
具体看下 Golang strings.ReplaceAll 的实现吧~
若不考虑 UTF-8编码、+Buffer,基本思路也就是遍历+替换
// Replace returns a copy of the string s with the first n
// non-overlapping instances of old replaced by new.
// If old is empty, it matches at the beginning of the string
// and after each UTF-8 sequence, yielding up to k+1 replacements
// for a k-rune string.
// If n < 0, there is no limit on the number of replacements.
func Replace(s, old, new string, n int) string {
if old == new || n == 0 {
return s // avoid allocation
}
// Compute number of replacements.
if m := Count(s, old); m == 0 {
return s // avoid allocation
} else if n < 0 || m < n {
n = m
}
// Apply replacements to buffer.
var b Builder
b.Grow(len(s) + n*(len(new)-len(old)))
start := 0
for i := 0; i < n; i++ {
j := start
if len(old) == 0 {
if i > 0 {
_, wid := utf8.DecodeRuneInString(s[start:])
j += wid
}
} else {
j += Index(s[start:], old)
}
b.WriteString(s[start:j])
b.WriteString(new)
start = j + len(old)
}
b.WriteString(s[start:])
return b.String()
}
// ReplaceAll returns a copy of the string s with all
// non-overlapping instances of old replaced by new.
// If old is empty, it matches at the beginning of the string
// and after each UTF-8 sequence, yielding up to k+1 replacements
// for a k-rune string.
func ReplaceAll(s, old, new string) string {
return Replace(s, old, new, -1)
}
替换核心就是下面三句
b.WriteString(s[start:j]) //start标记从旧字符串的哪个位置开始
b.WriteString(new) //写入替换数据
start = j + len(old) //移动start
总结
题是不难啦,但有点小启发 🤔
t := make([]byte, len(s)+n*(len(new)-len(old)))
在源码中很是常见,在创建slice的时候,尽可能的去指定好你需要的长度来避免扩容。👏
面试中,可以具体深入问 replace 怎么实现有看过源码么?若没有你会怎么实现呢?<( ̄▽ ̄)/
扩容+Buffer 和 UTF 编码都是值得提及的部分哦 (✧◡✧)