字符串解码问题 | 豆包MarsCode AI刷题

97 阅读4分钟

字符串解码问题 | 豆包MarsCode AI刷题

字符串解码问题 - MarsCode

简单题,可以学习golang中strings.Builder的使用

摘要

本文介绍了如何对字符串进行解码。通过替换特定字符并保持其他字符不变,我们可以高效地完成解码任务。本文提供了Python和Go的代码实现,时间复杂度为 O(N)O(N)


问题描述

给定字符串 SS 和替换规则:

  • 'x' 替换为 'y''y' 替换为 'x'
  • 'a' 替换为 'b''b' 替换为 'a'
  • 其他字符保持不变。

要求返回解码后的字符串。


示例

输入

N = 5, S = "xaytq"

输出

"ybxtq"


原理分析

替换规则

  • 遍历字符串 SS,对每个字符检查是否需要替换。
  • 若字符为 'x''y''a''b',则替换为相应的字符;否则保持原样。

算法步骤

  1. 初始化结果列表,用于存储解码后的字符。
  2. 遍历字符串,按照替换规则处理每个字符。
  3. 拼接结果列表为字符串并返回。

在 Go 中,strings.Builder 是用于高效构建字符串的工具。与直接使用字符串拼接相比,strings.Builder 可以减少内存分配的次数,从而提升性能,特别是在需要频繁拼接字符串的场景中。

使用 strings.Builder 的典型场景
  1. 字符串的高效拼接:避免多次内存分配。
  2. 动态生成长字符串:例如生成 HTML、JSON 等复杂结构。
  3. 性能优化:特别是在循环中拼接字符串时。

基本用法

以下是 strings.Builder 的常见用法:

package main

import (
	"fmt"
	"strings"
)

func main() {
	var builder strings.Builder

	// 使用 WriteString 添加字符串
	builder.WriteString("Hello")
	builder.WriteString(", ")
	builder.WriteString("World!")

	// 获取拼接后的字符串
	result := builder.String()

	fmt.Println(result) // 输出: Hello, World!
}

方法说明
1. WriteString(s string) (int, error)

Builder 中追加一个字符串。

builder.WriteString("Hello")

2. Write(b []byte) (int, error)

Builder 中追加字节切片。

builder.Write([]byte("Hello"))

3. WriteRune(r rune) (int, error)

Builder 中追加一个 Unicode 字符(rune)。

builder.WriteRune('世')
builder.WriteRune('界')

4. Grow(n int)

提前为 Builder 分配至少 n 字节的内存,减少后续内存分配次数。

builder.Grow(100) // 预分配 100 字节空间

5. String() string

获取当前 Builder 中的拼接结果。

result := builder.String()

6. Reset()

清空 Builder 的内容,可以重复使用。

builder.Reset()

示例:动态生成 JSON

strings.Builder 非常适合用来构造结构化字符串,例如 JSON。

package main

import (
	"fmt"
	"strings"
)

func main() {
	var builder strings.Builder

	builder.WriteString("{")
	builder.WriteString(`"name": "Alice", `)
	builder.WriteString(`"age": 25`)
	builder.WriteString("}")

	result := builder.String()
	fmt.Println(result)
}

输出:

{"name": "Alice", "age": 25}

示例:循环拼接字符串

在循环中使用 strings.Builder 拼接字符串时,可以显著提升性能。

package main

import (
	"fmt"
	"strings"
)

func main() {
	var builder strings.Builder
	builder.Grow(50) // 预分配空间,提升性能

	for i := 0; i < 5; i++ {
		builder.WriteString(fmt.Sprintf("Line %d\n", i+1))
	}

	fmt.Println(builder.String())
}

输出:

Line 1
Line 2
Line 3
Line 4
Line 5

性能对比:strings.Builder vs 字符串拼接

示例代码

package main

import (
	"strings"
	"testing"
)

func BenchmarkBuilder(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var builder strings.Builder
		builder.Grow(1000)
		for j := 0; j < 1000; j++ {
			builder.WriteString("a")
		}
		_ = builder.String()
	}
}

func BenchmarkStringConcat(b *testing.B) {
	for i := 0; i < b.N; i++ {
		str := ""
		for j := 0; j < 1000; j++ {
			str += "a"
		}
	}
}

结果

strings.Builder 的性能会显著优于直接的字符串拼接,尤其是拼接次数较多时。


注意事项
  1. 单线程使用
    • strings.Builder 不是线程安全的,不能在多个 goroutine 中同时使用。
  2. 不可复制
    • Builder 是一种带状态的对象,不能复制。如果复制一个 Builder,会导致未定义行为。

代码实现

Python代码

def solution(N: int, S: str) -> str:
    """
    根据字符的替换规则转换字符串 S:
    - 'x' 替换为 'y'
    - 'y' 替换为 'x'
    - 'a' 替换为 'b'
    - 'b' 替换为 'a'
    其余字符保持不变。
    """
    # 使用列表存储替换后的字符,避免频繁字符串拼接
    result = []

    # 遍历字符串 S 的每个字符
    for ch in S:
        if ch == 'x':
            result.append('y')
        elif ch == 'y':
            result.append('x')
        elif ch == 'a':
            result.append('b')
        elif ch == 'b':
            result.append('a')
        else:
            result.append(ch)

    # 将字符列表转换为字符串并返回
    return ''.join(result)


if __name__ == "__main__":
    # 测试用例
    print(solution(5, "xaytq") == "ybxtq")  # 应输出 True
    print(solution(6, "abcxyz") == "bacyxz")  # 应输出 True
    print(solution(3, "zzz") == "zzz")  # 应输出 True

Go语言代码

package main

import (
	"fmt"
	"strings"
)

func solution(N int, S string) string {
	var builder strings.Builder
	for i := 0; i < len(S); i++ {
		if S[i] == 'x' {
			builder.WriteRune('y')
		} else if S[i] == 'y' {
			builder.WriteRune('x')
		} else if S[i] == 'a' {
			builder.WriteRune('b')
		} else if S[i] == 'b' {
			builder.WriteRune('a')
		} else {
			builder.WriteRune(rune(S[i]))
		}
	}
	return builder.String()
}

func main() {
	fmt.Println(solution(5, "xaytq") == "ybxtq")
	fmt.Println(solution(6, "abcxyz") == "bacyxz")
	fmt.Println(solution(3, "zzz") == "zzz")
}