go - PS
go를 이용해 알고리즘 문제 풀이할 때 유용한 팁 정리
fmt
bufio.NewReader && fmt.Fscanf
대량의 입력을 받고자한다면, bufio
와 fmt.Fscan
을 사용하는 것이 좋습니다.
1
2
r := bufio.NewReader(os.Stdin)
fmt.Fscan(r, &v)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main
import (
"bufio"
"fmt"
"os"
)
var br = bufio.NewReader(os.Stdin)
func main() {
a := make([]int, 5)
for i = 0; i < len(a); i++ {
fmt.Fscan(br, &a[i])
}
}
여러개의 변수를 다음과 같이 Fscan
혹은 Fscanf
를 이용해서 읽을 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main
import (
"fmt"
"bufio"
"os"
)
var br = bufio.NewReader(os.Stdin)
func main {
var n int
var m int
fmt.Fscan(br, &n, &m)
// 혹은 다음과 같이 사용할 수 있습니다.
fmt.Fscanf(br, "%d %d\n", &n, &m)
}
출력의 경우,bufio
패키지를 사용하는 것이 출력할 결과의 개행문자가 많은 경우 손해일 수 있기에 fmt.Println
으로 충분합니다.
cmp
cmp.Compare && cmp.Or
cmp
패키지를 이용해 값 비교를 통한 정렬을 구현할 수 있습니다. cmp.Compare
함수로 go
기본 자료형에 대한 값 비교를 진행할 수 있습니다.
1
2
3
4
5
6
7
8
func Compare[T Ordered](x, y T) int
type Ordered interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
~float32 | ~float64 |
~string
}
cmp.Or
함수를 이용해 하나 이상의 값비교가 가능합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main
import (
"fmt"
"cmp"
"slices"
)
type Order struct {
Product string
Customer string
Price float64
}
func main() {
orders := []Order{
{"foo", "alice", 1.00},
{"bar", "bob", 3.00},
{"baz", "carol", 4.00},
{"foo", "alice", 2.00},
{"bar", "carol", 1.00},
{"foo", "bob", 4.00},
}
// customer 작은 순, product 작은순, price 큰순으로 정렬됩니다.
slices.SortFunc(orders, func(a, b Order) int {
return cmp.Or(
cmp.Compare(a.Customer, b.Customer),
cmp.Compare(a.Product, b.Product),
cmp.Compare(b.Price, a.Price)
)
})
}
slices
slices
패키지에는 슬라이스에 사용가능한 다양한 함수들이 정의되어 있습니다.
BinarySearch
1
func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool)
오름차순으로 정렬된 기본 타입 슬라이스에 적용가능한 함수입니다.
만약 찾으려는 값이 슬라이스에 존재한다면, 찾으려는 값의 인덱스가 없다면 삽입될 인덱스의 값과 찾았는지 여부가 리턴됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main
import (
"fmt"
"slices"
)
func main() {
names := []string{"Alice", "Bob", "Vera"}
n, found := slices.BinarySearch(names, "Vera")
fmt.Println("Vera: ", n, found)
n, found = slices.BinarySearch(names, "Bill")
fmt.Println("Bill: ", n, found)
}
// Vera: 2 true
// Bill: 1 false
BinarySearchFunc
메소드로는 기본 타입 뿐만 아니라, 어떤 타입이든 탐색가능합니다.
1
func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool)
먼저 슬라이스는 cmp 함수를 이용해서 오름차순으로 정렬되어 있어야합니다. 리턴 결과는 BinarySearch
와 동일합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main
import (
"fmt"
"slices"
"strings"
)
type Person struct {
Name string
Age int
}
func main() {
people := []Person {
{"Alice", 55},
{"Bob", 24},
{"Gopher", 13}
}
n, found := slices.BinarySearchFunc(people, Person{"Bob", 0}, func(a, b Person) int {
return strings.Compare(a.Name, b.Name)
})
fmt.Println("Bob: ",n,found)
}
// Bob: 1 true
Max && Min
최대 최소를 구하는 함수도 유사하게, Max
, Min
이 있고, 비교함수를 추가할 수 있는 MaxFunc
, MinFunc
가 있습니다.
Sort
기본 타입 슬라이스인 경우, Sort
를 이용해서 정렬 가능합니다. 그렇지 않은 경우 SortFunc
를 이용해서 원하는 순서로 정렬할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main
import (
"cmp"
"fmt"
"slices"
"strings"
)
func main() {
type Person struct {
Name string
Age int
}
people := []Person{
{"Gopher", 13},
{"Alice", 55},
{"Bob", 24},
{"Alice", 20},
}
slices.SortFunc(people, func(a, b Person) int {
if n := strings.Compare(a.Name, b.Name); n != 0 {
return n
}
// If names are equal, order by age
return cmp.Compare(a.Age, b.Age)
})
fmt.Println(people)
}
container
heap
container/heap
패키지를 사용해서 우선순위 큐를 사용할 수 있습니다. 우선순위 큐를 구현하기 위해서는 다음과 같이 구현할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package main
import (
"container/heap"
"fmt"
)
type Item struct {
value string
priority int
index int
}
// heap.Interface를 구현하는 PriorityQueue 타입을 선언합니다.
type PriorityQueue []*Item
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
// 우선 순위가 높을 수록 상단에 위치합니다.
return pq[i].priority > pq[j].priority
}
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].index = i
pq[j].index = j
}
func (pq *PriorityQueue) Push(x any) {
n := len(*pq)
item := x.(*Item)
item.index = n
*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() any {
old := *pq
n := len(old)
item := old[n-1]
old[n-1] = nil
item.index = -1
*pq = old[0 : n-1]
return item
}
func main() {
items := map[string]int{
"banana": 3, "apple": 2, "pear": 4,
}
pq := make(PriorityQueue, len(items))
i := 0
for value, priority := range items {
pq[i] = &Item{
value: value,
priority: priority,
index: i,
}
i++
}
heap.Init(&pq)
item := &Item{
value: "orange",
priority: 1,
}
heap.Push(&pq, item)
for pq.Len() > 0 {
item := heap.Pop(&pq).(*Item)
fmt.Printf("%.2d:%s\n", item.priority, item.value)
}
}
/*
04:pear
03:banana
02:apple
01:orange
*/
같은 패키지 안에서 선언한 타입에 대해서만 리시버 함수를 구현할 수 있기에, PriorityQueue
타입을 만들었고, Push
, Pop
기능을 구현했습니다. 추가로 내부에서 우선순위 큐 동작을 위한 Less
, Len
, Swap
함수를 정의했습니다.
list
container/list
패키지에서 제공하는 인터페이스를 이용해서 스택과 큐를 구현할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main
import (
"container/list"
"fmt"
)
type Item struct {
value string
priority int
}
func (e Item) String() string {
return fmt.Sprintf("%s %d", e.value, e.priority)
}
func main() {
l := list.New()
l.PushBack(Item{"hello", 1})
l.PushBack(Item{"world", 2})
for e := l.Front(); e != nil; e = e.Next() {
fmt.Println(e.Value)
}
l.PushBack(Item{"hello", 1})
l.PushBack(Item{"world", 2})
for e := l.Back(); e != nil; e = e.Prev() {
fmt.Println(e.Value)
}
}
etc
2차원 배열 초기화
1
2
3
4
5
connected := make([][] bool, n)
for i := 0; i < n; i++ {
connected[i] = make([]bool, n)
}
실행 환경 버전 확인
1
2
3
4
5
6
7
8
import (
"fmt"
"runtime"
)
func main() {
fmt.Printf("The application was built with the Go version: %s\n", runtime.Version())
}