Skip to content

Commit

Permalink
Merge 0e23969 into b00c67c
Browse files Browse the repository at this point in the history
  • Loading branch information
vaskoz committed Mar 27, 2019
2 parents b00c67c + 0e23969 commit 9dde6a0
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 44 deletions.
69 changes: 41 additions & 28 deletions day72/problem.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ var errInfiniteLoop = errors.New("loop detected")
// AdjacencyMatrix represents a sparse adjacency matrix.
type AdjacencyMatrix map[int]map[int]struct{}

// Node is a character representation of a node in a graph.
type Node rune

// Edge represents a directed edge going 'From' and 'To' a different node.
// Nodes are represented by integers from 0..N.
type Edge struct {
Expand All @@ -23,45 +26,55 @@ func ErrInfiniteLoop() error {
// LargestPathValue takes a slice of runes representing nodes.
// Edges represents all the directed edges.
// Returns the largest path value or an error if an infinite loop is detected.
func LargestPathValue(nodes []rune, edges []Edge) (int, error) {
func LargestPathValue(nodes []Node, edges []Edge) (int, error) {
graph := buildAdjacencyMatrix(edges)
largest := 0
for from := range graph {
visited := make([]bool, len(nodes))
counts := make(map[rune]int)
stack := make([]int, 0, len(nodes))
stack = append(stack, from)
for len(stack) != 0 {
var v int
v, stack = stack[len(stack)-1], stack[:len(stack)-1]
if !visited[v] {
visited[v] = true
counts[nodes[v]]++
for k := range graph[v] {
stack = append(stack, k)
}
for _, count := range counts {
if count > largest {
largest = count
}
}
} else {
return 0, ErrInfiniteLoop() // cycle found
}
visited := make(map[int]struct{}, len(nodes))
freq := make(map[Node]int)
var largest int
for start := range graph {
if count, err := dfsBacktracking(graph, nodes, start, visited, freq); err != nil {
return 0, err
} else if count > largest {
largest = count
}
}
return largest, nil
}

func dfsBacktracking(g AdjacencyMatrix, nodes []Node, n int, visited map[int]struct{}, freq map[Node]int) (int, error) {
visited[n] = struct{}{}
freq[nodes[n]]++
var max int
var err error
if len(g[n]) == 0 {
for _, count := range freq {
if count > max {
max = count
}
}
} else {
for next := range g[n] {
if _, seen := visited[next]; seen {
return 0, ErrInfiniteLoop()
} else if v, err := dfsBacktracking(g, nodes, next, visited, freq); err != nil {
return 0, err
} else if v > max {
max = v
}
}
}
freq[nodes[n]]--
delete(visited, n)
return max, err
}

func buildAdjacencyMatrix(edges []Edge) AdjacencyMatrix {
graph := make(AdjacencyMatrix)
for _, edge := range edges {
if _, found := graph[edge.From]; found {
graph[edge.From][edge.To] = struct{}{}
} else {
if _, found := graph[edge.From]; !found {
graph[edge.From] = make(map[int]struct{})
graph[edge.From][edge.To] = struct{}{}
}
graph[edge.From][edge.To] = struct{}{}
}
return graph
}
34 changes: 18 additions & 16 deletions day72/problem_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,31 @@ package day72

import "testing"

func TestLargestPathValue(t *testing.T) {
t.Parallel()
nodes := []rune("ABACA")
edges := []Edge{{0, 1}, {0, 2}, {2, 3}, {3, 4}}
expected := 3
if result, _ := LargestPathValue(nodes, edges); result != expected {
t.Errorf("Expected %v but got %v", expected, result)
}
var testcases = []struct {
nodes []Node
edges []Edge
expected int
expectedErr error
}{
{[]Node("ABACA"), []Edge{{0, 1}, {0, 2}, {2, 3}, {3, 4}}, 3, nil},
{[]Node("ABAACB"), []Edge{{0, 1}, {0, 2}, {0, 3}, {1, 4}, {4, 5}}, 2, nil},
{[]Node("A"), []Edge{{0, 0}}, 0, ErrInfiniteLoop()},
{[]Node("AAAA"), []Edge{{0, 1}, {1, 2}, {2, 3}, {3, 0}}, 0, ErrInfiniteLoop()},
}

func TestLargestPathValueInfiniteLoop(t *testing.T) {
func TestLargestPathValue(t *testing.T) {
t.Parallel()
nodes := []rune("A")
edges := []Edge{{0, 0}}
if _, err := LargestPathValue(nodes, edges); err != ErrInfiniteLoop() {
t.Errorf("Expected an error")
for _, tc := range testcases {
if result, err := LargestPathValue(tc.nodes, tc.edges); result != tc.expected || err != tc.expectedErr {
t.Errorf("Expected (%v,%v) but got (%v,%v)", tc.expected, tc.expectedErr, result, err)
}
}
}

func BenchmarkLargestPathValue(b *testing.B) {
nodes := []rune("ABACA")
edges := []Edge{{0, 1}, {0, 2}, {2, 3}, {3, 4}}
for i := 0; i < b.N; i++ {
LargestPathValue(nodes, edges)
for _, tc := range testcases {
LargestPathValue(tc.nodes, tc.edges)
}
}
}

0 comments on commit 9dde6a0

Please sign in to comment.