2020 day 10 - memoized or dynamic programming to calculate paths/possibilities, ~830

This commit is contained in:
alexchao26
2020-12-10 00:46:21 -05:00
parent 632d524c31
commit b9a74cf122
2 changed files with 161 additions and 11 deletions
+87 -6
View File
@@ -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
View File
@@ -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)
}
})
}
}