Skip to content

Commit f1ba5a4

Browse files
committed
init commit
0 parents commit f1ba5a4

File tree

8 files changed

+296
-0
lines changed

8 files changed

+296
-0
lines changed

.github/workflows/go.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Go
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
branches:
9+
- master
10+
11+
jobs:
12+
build:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v2
17+
- name: Setup Go
18+
uses: actions/setup-go@v2
19+
with:
20+
go-version: 1.16
21+
- name: Build
22+
run: go build -v ./...
23+
- name: Test
24+
run: go test -v -cover ./...
25+
- name: Benchmark
26+
run: go test -benchmem -run=none -bench ^BenchmarkTest$ sol/sol

.gitignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# If you prefer the allow list template instead of the deny list, see community template:
2+
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3+
#
4+
# Binaries for programs and plugins
5+
*.exe
6+
*.exe~
7+
*.dll
8+
*.so
9+
*.dylib
10+
11+
# Test binary, built with `go test -c`
12+
*.test
13+
14+
# Output of the go coverage tool, specifically when used with LiteIDE
15+
*.out
16+
17+
# Dependency directories (remove the comment below to include it)
18+
# vendor/
19+
20+
# Go workspace file
21+
go.work

.gitlab-ci.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
stages:
2+
- test
3+
build and test:
4+
image: golang:1.16
5+
stage: test
6+
script:
7+
- go build -v ./...
8+
- go test -v -cover ./...
9+
- go test -benchmem -run=none -bench ^BenchmarkTest$ sol/sol

.husky/pre-commit

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/bash
2+
go test -v -cover ./...

README.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# golang_reconstruct_itinerary
2+
3+
You are given a list of airline `tickets` where `tickets[i] = [fromi, toi]` represent the departure and the arrival airports of one flight. Reconstruct the itinerary in order and return it.
4+
5+
All of the tickets belong to a man who departs from `"JFK"`, thus, the itinerary must begin with `"JFK"`. If there are multiple valid itineraries, you should return the itinerary that has the smallest lexical order when read as a single string.
6+
7+
- For example, the itinerary `["JFK", "LGA"]` has a smaller lexical order than `["JFK", "LGB"]`.
8+
9+
You may assume all tickets form at least one valid itinerary. You must use all the tickets once and only once.
10+
11+
## Examples
12+
13+
**Example 1:**
14+
15+
![https://assets.leetcode.com/uploads/2021/03/14/itinerary1-graph.jpg](https://assets.leetcode.com/uploads/2021/03/14/itinerary1-graph.jpg)
16+
17+
```
18+
Input: tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]]
19+
Output: ["JFK","MUC","LHR","SFO","SJC"]
20+
21+
```
22+
23+
**Example 2:**
24+
25+
![https://assets.leetcode.com/uploads/2021/03/14/itinerary2-graph.jpg](https://assets.leetcode.com/uploads/2021/03/14/itinerary2-graph.jpg)
26+
27+
```
28+
Input: tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
29+
Output: ["JFK","ATL","JFK","SFO","ATL","SFO"]
30+
Explanation: Another possible reconstruction is ["JFK","SFO","ATL","JFK","ATL","SFO"] but it is larger in lexical order.
31+
32+
```
33+
34+
**Constraints:**
35+
36+
- `1 <= tickets.length <= 300`
37+
- `tickets[i].length == 2`
38+
- `fromi.length == 3`
39+
- `toi.length == 3`
40+
- $`from_i`$ and $`to_i`$ consist of uppercase English letters.
41+
- $`from_i$ != $to_i$`
42+
43+
## 解析
44+
45+
題目給定一個整數矩陣 tickets , 其中每個 entry ticket[i] = [$location_1$, $location_2$] 代表
46+
47+
$location_1$ 到 $location_2$ 有一個 path 可以經過
48+
49+
要求寫一個演算法
50+
51+
找出從 “JFK” 出發按照給定的 tickets 以及地點字母排序 走訪完所有 path 的一個可行順序
52+
53+
首先是這次的 path 是有順序的
54+
55+
所以關鍵是要透過 tickets 做出 adjacency list
56+
57+
然後這些 adjacency list 需要按照字母順序排列
58+
59+
一個可行的作法是先把 tickets 先做字母排序
60+
61+
然後在照順序做 adjacency list
62+
63+
然後依序從 “JFK” 做 DFS
64+
65+
然後每次經過一個地點 就把原本的 adjacency list 的 path消去一個
66+
67+
![](https://i.imgur.com/nK2J1eh.png)
68+
69+
## 程式碼
70+
```go
71+
package sol
72+
73+
import (
74+
"sort"
75+
"strings"
76+
)
77+
78+
type Locations []string
79+
80+
func findItinerary(tickets [][]string) []string {
81+
sortedTickets := SortInput(tickets)
82+
adjacencyMap := make(map[string]Locations)
83+
for _, ticket := range sortedTickets {
84+
adjacencyMap[ticket[0]] = append(adjacencyMap[ticket[0]], ticket[1])
85+
}
86+
result := []string{"JFK"}
87+
var dfs func(location string) bool
88+
dfs = func(location string) bool {
89+
if len(result) == len(tickets)+1 {
90+
return true
91+
}
92+
adjacencyList, ok := adjacencyMap[location]
93+
if !ok {
94+
return false
95+
}
96+
temp := make([]string, len(adjacencyList))
97+
copy(temp, adjacencyList)
98+
for _, loc := range adjacencyList {
99+
result = append(result, loc)
100+
adjacencyList = adjacencyList[1:]
101+
adjacencyMap[location] = adjacencyList
102+
if dfs(loc) {
103+
return true
104+
}
105+
result = result[:len(result)-1]
106+
adjacencyList = append(adjacencyList, loc)
107+
adjacencyMap[location] = adjacencyList
108+
}
109+
return false
110+
}
111+
dfs("JFK")
112+
return result
113+
}
114+
115+
func SortInput(tickets [][]string) [][]string {
116+
temp := make([]string, len(tickets))
117+
result := make([][]string, len(tickets))
118+
for idx, ticket := range tickets {
119+
temp[idx] = ticket[0] + "," + ticket[1]
120+
}
121+
sort.Strings(temp)
122+
for idx, item := range temp {
123+
result[idx] = strings.Split(item, ",")
124+
}
125+
return result
126+
}
127+
128+
```
129+
## 困難點
130+
131+
1. 理解如何達成有序的找到 Location
132+
2. 對 DFS 需要去理解
133+
134+
## Solve Point
135+
136+
- [x] 需要知道如何找到鄰近的 Location
137+
- [x] 建立 adjacency list 時需要透過 sort 去處理

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module sol
2+
3+
go 1.16

sol/solution.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package sol
2+
3+
import (
4+
"sort"
5+
"strings"
6+
)
7+
8+
type Locations []string
9+
10+
func findItinerary(tickets [][]string) []string {
11+
sortedTickets := SortInput(tickets)
12+
adjacencyMap := make(map[string]Locations)
13+
for _, ticket := range sortedTickets {
14+
adjacencyMap[ticket[0]] = append(adjacencyMap[ticket[0]], ticket[1])
15+
}
16+
result := []string{"JFK"}
17+
var dfs func(location string) bool
18+
dfs = func(location string) bool {
19+
if len(result) == len(tickets)+1 {
20+
return true
21+
}
22+
adjacencyList, ok := adjacencyMap[location]
23+
if !ok {
24+
return false
25+
}
26+
temp := make([]string, len(adjacencyList))
27+
copy(temp, adjacencyList)
28+
for _, loc := range adjacencyList {
29+
result = append(result, loc)
30+
adjacencyList = adjacencyList[1:]
31+
adjacencyMap[location] = adjacencyList
32+
if dfs(loc) {
33+
return true
34+
}
35+
result = result[:len(result)-1]
36+
adjacencyList = append(adjacencyList, loc)
37+
adjacencyMap[location] = adjacencyList
38+
}
39+
return false
40+
}
41+
dfs("JFK")
42+
return result
43+
}
44+
45+
func SortInput(tickets [][]string) [][]string {
46+
temp := make([]string, len(tickets))
47+
result := make([][]string, len(tickets))
48+
for idx, ticket := range tickets {
49+
temp[idx] = ticket[0] + "," + ticket[1]
50+
}
51+
sort.Strings(temp)
52+
for idx, item := range temp {
53+
result[idx] = strings.Split(item, ",")
54+
}
55+
return result
56+
}

sol/solution_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package sol
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func BenchmarkTest(b *testing.B) {
9+
tickets := [][]string{{"MUC", "LHR"}, {"JFK", "MUC"}, {"SFO", "SJC"}, {"LHR", "SFO"}}
10+
for idx := 0; idx < b.N; idx++ {
11+
findItinerary(tickets)
12+
}
13+
}
14+
15+
func Test_findItinerary(t *testing.T) {
16+
type args struct {
17+
tickets [][]string
18+
}
19+
tests := []struct {
20+
name string
21+
args args
22+
want []string
23+
}{
24+
{
25+
name: "tickets = [[MUC,LHR],[JFK,MUC],[SFO,SJC],[LHR,SFO]]",
26+
args: args{tickets: [][]string{{"MUC", "LHR"}, {"JFK", "MUC"}, {"SFO", "SJC"}, {"LHR", "SFO"}}},
27+
want: []string{"JFK", "MUC", "LHR", "SFO", "SJC"},
28+
},
29+
{
30+
name: "tickets = [[JFK,SFO],[JFK,ATL],[SFO,ATL],[ATL,JFK],[ATL,SFO]]",
31+
args: args{tickets: [][]string{{"JFK", "SFO"}, {"JFK", "ATL"}, {"SFO", "ATL"}, {"ATL", "JFK"}, {"ATL", "SFO"}}},
32+
want: []string{"JFK", "ATL", "JFK", "SFO", "ATL", "SFO"},
33+
},
34+
}
35+
for _, tt := range tests {
36+
t.Run(tt.name, func(t *testing.T) {
37+
if got := findItinerary(tt.args.tickets); !reflect.DeepEqual(got, tt.want) {
38+
t.Errorf("findItinerary() = %v, want %v", got, tt.want)
39+
}
40+
})
41+
}
42+
}

0 commit comments

Comments
 (0)