mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-05-21 12:23:27 +02:00
2020 day 10 - memoized or dynamic programming to calculate paths/possibilities, ~830
This commit is contained in:
+87
-6
@@ -3,8 +3,10 @@ package main
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/alexchao26/advent-of-code-go/algo"
|
||||
"github.com/alexchao26/advent-of-code-go/util"
|
||||
)
|
||||
|
||||
@@ -26,17 +28,34 @@ func main() {
|
||||
}
|
||||
|
||||
func part1(input string) int {
|
||||
parsed := parseInput(input)
|
||||
_ = parsed
|
||||
nums := parseInput(input)
|
||||
nums = append(nums, util.MaxInts(nums...)+3)
|
||||
sort.Ints(nums)
|
||||
|
||||
return 0
|
||||
var oneDiff, threeDiff int
|
||||
var currentJoltage int
|
||||
for _, v := range nums {
|
||||
switch v - currentJoltage {
|
||||
case 1: // check for 1 diff first, so no adapters are skipped
|
||||
oneDiff++
|
||||
case 3:
|
||||
threeDiff++
|
||||
default:
|
||||
panic("adpaters not connected by 3 or 1")
|
||||
}
|
||||
currentJoltage = v
|
||||
}
|
||||
|
||||
return oneDiff * threeDiff
|
||||
}
|
||||
|
||||
func part2(input string) int {
|
||||
parsed := parseInput(input)
|
||||
_ = parsed
|
||||
nums := parseInput(input)
|
||||
nums = append(nums, util.MaxInts(nums...)+3)
|
||||
sort.Ints(nums)
|
||||
|
||||
return 0
|
||||
// return dynamicProgramming(input)
|
||||
return memoCountPossibilities(nums, 0)
|
||||
}
|
||||
|
||||
func parseInput(input string) []int {
|
||||
@@ -49,3 +68,65 @@ func parseInput(input string) []int {
|
||||
|
||||
return ans
|
||||
}
|
||||
|
||||
// storing memo in global state isn't ideal... but it's fastser to code
|
||||
var memo = map[string]int{}
|
||||
|
||||
func memoCountPossibilities(nums []int, lastJolt int) int {
|
||||
// if in memo, return that value
|
||||
str := makeMemoKey(nums, lastJolt)
|
||||
if v, ok := memo[str]; ok {
|
||||
return v
|
||||
}
|
||||
|
||||
// if all adapters used up, return 1
|
||||
if len(nums) == 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// create a recursive call for each adapter within 3 of the lastJoltage
|
||||
var count int
|
||||
for i, v := range nums {
|
||||
if v-lastJolt <= 3 {
|
||||
count += memoCountPossibilities(nums[i+1:], v)
|
||||
} else { // stop counting if the joltage diff is too larger (>3)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// update memo
|
||||
memo[str] = count
|
||||
|
||||
return count
|
||||
}
|
||||
func makeMemoKey(nums []int, lastJolt int) string {
|
||||
ans := algo.IntToStr(lastJolt) + "x"
|
||||
for _, v := range nums {
|
||||
ans += algo.IntToStr(v)
|
||||
}
|
||||
return ans
|
||||
}
|
||||
|
||||
func dynamicProgramming(input string) int {
|
||||
nums := parseInput(input)
|
||||
nums = append(nums, util.MaxInts(nums...)+3, 0)
|
||||
sort.Ints(nums)
|
||||
|
||||
// initialize table with "1 way" to get to zero jolts
|
||||
table := make([]int, len(nums))
|
||||
table[0] = 1
|
||||
|
||||
for i := 1; i < len(nums); i++ {
|
||||
currentJolts := nums[i]
|
||||
for j := i - 1; j >= 0; j-- {
|
||||
// add the ways to get to currentJolts that are within 3 jolts
|
||||
if currentJolts-nums[j] <= 3 {
|
||||
table[i] += table[j]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return table[len(table)-1]
|
||||
}
|
||||
|
||||
+74
-5
@@ -1,14 +1,63 @@
|
||||
package main
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/alexchao26/advent-of-code-go/util"
|
||||
)
|
||||
|
||||
var exampleInputs = []string{`16
|
||||
10
|
||||
15
|
||||
5
|
||||
1
|
||||
11
|
||||
7
|
||||
19
|
||||
6
|
||||
12
|
||||
4`,
|
||||
`28
|
||||
33
|
||||
18
|
||||
42
|
||||
31
|
||||
14
|
||||
46
|
||||
20
|
||||
48
|
||||
47
|
||||
24
|
||||
23
|
||||
49
|
||||
45
|
||||
19
|
||||
38
|
||||
39
|
||||
11
|
||||
1
|
||||
32
|
||||
25
|
||||
35
|
||||
8
|
||||
17
|
||||
7
|
||||
9
|
||||
4
|
||||
2
|
||||
34
|
||||
10
|
||||
3`,
|
||||
}
|
||||
|
||||
var tests1 = []struct {
|
||||
name string
|
||||
want int
|
||||
input string
|
||||
// add extra args if needed
|
||||
}{
|
||||
// {"actual", ACTUAL_ANSWER, util.ReadFile("input.txt")},
|
||||
{"example 1", 35, exampleInputs[0]},
|
||||
{"example 2", 220, exampleInputs[1]},
|
||||
{"actual", 2176, util.ReadFile("input.txt")},
|
||||
}
|
||||
|
||||
func TestPart1(t *testing.T) {
|
||||
@@ -25,9 +74,10 @@ var tests2 = []struct {
|
||||
name string
|
||||
want int
|
||||
input string
|
||||
// add extra args if needed
|
||||
}{
|
||||
// {"actual", ACTUAL_ANSWER, util.ReadFile("input.txt")},
|
||||
{"example 1", 8, exampleInputs[0]},
|
||||
{"example 2", 19208, exampleInputs[1]},
|
||||
{"actual", 18512297918464, util.ReadFile("input.txt")},
|
||||
}
|
||||
|
||||
func TestPart2(t *testing.T) {
|
||||
@@ -39,3 +89,22 @@ func TestPart2(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_dynamicProgramming(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want int
|
||||
input string
|
||||
}{
|
||||
{"example 1", 8, exampleInputs[0]},
|
||||
{"example 2", 19208, exampleInputs[1]},
|
||||
{"actual", 18512297918464, util.ReadFile("input.txt")},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := dynamicProgramming(tt.input); got != tt.want {
|
||||
t.Errorf("dynamicProgramming() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user