调整麻烦
Question
最后,我们搬出营地!
当我们开始离开营地时,其中一个精灵为我们提供了一个通信设备,这不足为奇,我们得到了唯一的故障设备...
设备接收从字符列表构建的信号流,为了修复我们的设备,我们需要能够找到 启动启动标记。
第1部分
我们被告知,数据包的开始定义为一系列连续四个不同的字符。
鉴于我们的签名,我们需要确定在出现第一个标记之前应该处理多少个字符,或者换句话说,在我们的标记末尾索引。
例如,mjq<start>jpqm<end>gbljsphdztnvjfqwrcgsmlb
<start>
和<end>
代表标记的开始和结尾
意味着答案应为 7 (m
索引)
基本上我们需要完成的工作是连续找到4个连续的字符,有多种方法可以做到这一点,但是我们将使用Set来计算给定范围内的唯一字符数量,即i
-> i+4
<< br>
在该范围的每个位置,我们将采用字符并将其添加到我们的集合中,如果设定大小为4,则在范围的末尾,我们获得了赢家,我们可以返回当前的索引i + 4
。
set是一种数据结构,可以保证每个键的唯一性,在GO中,没有内置类型,但是我们可以轻松地使用
map[rune]bool
类型创建一个集合,以使其更有趣,让我们创建创建通用集软件包
放
我们将创建一个名为set
的软件包,其中一个名为SimpleSet
的结构将支持一组基本的操作
- 添加
- 有
- 大小
这是我们的SimpleSet
的代码
package set
type SimpleSet[T comparable] struct {
items map[T]bool
}
func NewSimpleSet[T comparable](values ...T) *SimpleSet[T] {
m := make(map[T]bool)
return &SimpleSet[T]{
items: m,
}
}
func (s *SimpleSet[T]) Add(key T) {
s.items[key] = true
}
func (s *SimpleSet[T]) Has(key T) bool {
_, ok := s.items[key]
return ok
}
func (s *SimpleSet[T]) Size() int {
return len(s.items)
}
我正在使用仿制药使此组在未来几天内有用,您可以阅读更多有关它的信息。
我没有得到什么,直到最近才有仿制药,想象一下为每种类型重复我们的设置相同的代码!
配备了我们的新套装,让我们解决第1部分!
func Part1(raw string) int {
for i := range raw {
set := set.NewSimpleSet[rune]()
for _, c := range raw[i : i+4] {
set.Add(c)
}
if set.Size() == 4 {
return i + 4
}
}
return -1
}
第2部分
完全像第1部分,但现在标记需要连续14个字符
我们可以采用我们的第1部分解决方案,并接受偏移以适合这两个部分
func Part1(raw string, offset int) int {
for i := range raw {
set := set.NewSimpleSet[rune]()
for _, c := range raw[i : i+offset] {
set.Add(c)
}
if set.Size() == offset {
return i + offset
}
}
return -1
}
我们的第2部分解决方案将是Part1(input, 14
。
,如果已经在我们的集合中,在我们做任何首先需要测量当前解决方案之前,可以通过提早返回来优化解决方案。
。使用Go benchmarks功能可以轻松完成这一点。
创建一个新文件main_test.go
并在那里写下我们的基准
package main
import (
"testing"
"github.com/galElmalah/aoc-2022/util"
)
func BenchmarkPart1(b *testing.B) {
input := util.ReadFile("./input.txt")
// run the Fib function b.N times
for n := 0; n < b.N; n++ {
Part1(input, 4)
}
}
func BenchmarkPart2(b *testing.B) {
input := util.ReadFile("./input.txt")
// run the Fib function b.N times
for n := 0; n < b.N; n++ {
Part1(input, 14)
}
}
运行go test -bench=. -count 3
导致
BenchmarkPart1-8 3819 285783 ns/op
BenchmarkPart1-8 3873 285734 ns/op
BenchmarkPart1-8 4021 284767 ns/op
BenchmarkPart2-8 1086 1083411 ns/op
BenchmarkPart2-8 1083 1073575 ns/op
BenchmarkPart2-8 1046 1075867 ns/op
现在让我们将以下if
添加到我们的内部循环
if set.Has(c) {
break
}
重新运行基准
BenchmarkPart1-8 3607 296341 ns/op
BenchmarkPart1-8 3748 294505 ns/op
BenchmarkPart1-8 3734 289663 ns/op
BenchmarkPart2-8 2490 465996 ns/op
BenchmarkPart2-8 2526 454670 ns/op
BenchmarkPart2-8 2541 451878 ns/op
我们可以看到,对于第1部分,几乎没有改进,但是对于第2部分,早期的回报确实有明显的差异,很棒!
就是这样,我们创建了自己的设置数据结构,并使用GO基准来优化我们的解决方案。
我希望您喜欢并学到了一些新事物,因为我肯定做了!
您可以找到完整的代码here
感谢您的阅读!