个人评价:又是一道内置函数 5s 解题(迷惑脸?)但是个人认为还是蛮值得深入的

题目难度:🌟 (参考 LeeCode 简单🌟 、中等🌟 🌟 、困难🌟 🌟 🌟 )

另,通常算法题会考察分析时间复杂度和空间复杂度,可参考笔者之前的文章

「数据结构&算法」必知必会系列:3. 时间 & 空间复杂度(下)

替换空格

题目描述

剑指 Offer 05. 替换空格

请实现一个函数,把字符串 s 中的每个空格替换成”%20”。

示例 1:

输入:s = “We are happy.”

输出:“We%20are%20happy.”

限制:

0 <= s 的长度 <= 10000

解题思路

方法一

replace 函数不少语言应该都支持吧?或者正则匹配也成

不管了,直接上 😂

  1. func replaceSpace(s string) string {
  2. return strings.ReplaceAll(s, " ", "%20")
  3. }

方法二

好吧,好歹也是算法的题目,想想遍历实现以及这题的初衷?

字符串通常被设计成「不可变」的类型(Go、Python、Java),即无法直接修改字符串的某一位字符,需要新建一个字符串实现。

那么,我们通常会处理为:

  • 初始化一个 list
  • 遍历列表 s 中的每个字符 c
  • 当 c 为空格时:向 list 后添加字符串 “%20”
  • 当 c 不为空格时:向 list 后添加字符 c
  • 将列表 list 转化为字符串并返回

复杂度?🙌 时间&空间均为 O(n)

C++ 中,字符串可变,参考先扩展后填充的方式,示例图如下:

题目引申

具体看下 Golang strings.ReplaceAll 的实现吧~

若不考虑 UTF-8编码、+Buffer,基本思路也就是遍历+替换

  1. // Replace returns a copy of the string s with the first n
  2. // non-overlapping instances of old replaced by new.
  3. // If old is empty, it matches at the beginning of the string
  4. // and after each UTF-8 sequence, yielding up to k+1 replacements
  5. // for a k-rune string.
  6. // If n < 0, there is no limit on the number of replacements.
  7. func Replace(s, old, new string, n int) string {
  8. if old == new || n == 0 {
  9. return s // avoid allocation
  10. }
  11. // Compute number of replacements.
  12. if m := Count(s, old); m == 0 {
  13. return s // avoid allocation
  14. } else if n < 0 || m < n {
  15. n = m
  16. }
  17. // Apply replacements to buffer.
  18. var b Builder
  19. b.Grow(len(s) + n*(len(new)-len(old)))
  20. start := 0
  21. for i := 0; i < n; i++ {
  22. j := start
  23. if len(old) == 0 {
  24. if i > 0 {
  25. _, wid := utf8.DecodeRuneInString(s[start:])
  26. j += wid
  27. }
  28. } else {
  29. j += Index(s[start:], old)
  30. }
  31. b.WriteString(s[start:j])
  32. b.WriteString(new)
  33. start = j + len(old)
  34. }
  35. b.WriteString(s[start:])
  36. return b.String()
  37. }
  38. // ReplaceAll returns a copy of the string s with all
  39. // non-overlapping instances of old replaced by new.
  40. // If old is empty, it matches at the beginning of the string
  41. // and after each UTF-8 sequence, yielding up to k+1 replacements
  42. // for a k-rune string.
  43. func ReplaceAll(s, old, new string) string {
  44. return Replace(s, old, new, -1)
  45. }

替换核心就是下面三句

  1. b.WriteString(s[start:j]) //start标记从旧字符串的哪个位置开始
  2. b.WriteString(new) //写入替换数据
  3. start = j + len(old) //移动start

总结

题是不难啦,但有点小启发 🤔

  1. t := make([]byte, len(s)+n*(len(new)-len(old)))

在源码中很是常见,在创建slice的时候,尽可能的去指定好你需要的长度来避免扩容。👏

面试中,可以具体深入问 replace 怎么实现有看过源码么?若没有你会怎么实现呢?<( ̄▽ ̄)/

扩容+Buffer 和 UTF 编码都是值得提及的部分哦 (✧◡✧)