Solve #2
This commit is contained in:
parent
26fb260a0c
commit
d2922dd41d
3 changed files with 210 additions and 0 deletions
138
2025/two/two.go
Normal file
138
2025/two/two.go
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func scanComma(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||
if atEOF && len(data) == 0 {
|
||||
return 0, nil, nil
|
||||
}
|
||||
if i := bytes.IndexByte(data, ','); i > 0 {
|
||||
return i + 1, data[0:i], nil
|
||||
}
|
||||
if atEOF {
|
||||
if len(data) > 0 && data[len(data)-1] == '\n' {
|
||||
return len(data), data[0 : len(data)-1], nil
|
||||
}
|
||||
return len(data), data, nil
|
||||
}
|
||||
return 0, nil, nil
|
||||
|
||||
}
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func intPow(base int, exponent int) int {
|
||||
|
||||
if exponent == 0 {
|
||||
return 1
|
||||
} else if exponent == 1 {
|
||||
return base
|
||||
}
|
||||
|
||||
val := base
|
||||
remaining_mults := exponent - 1
|
||||
for ; remaining_mults > 0; remaining_mults-- {
|
||||
val = val * base
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func makeCandidateInt(prefix int, n_repeats int) (int, error) {
|
||||
prefixStr := strconv.Itoa(prefix)
|
||||
|
||||
var candidateBuilder strings.Builder
|
||||
|
||||
for ; n_repeats > 0; n_repeats-- {
|
||||
candidateBuilder.WriteString(prefixStr)
|
||||
}
|
||||
|
||||
return strconv.Atoi(candidateBuilder.String())
|
||||
|
||||
}
|
||||
|
||||
func largestPrefix(rangeEnd string) (int, error) {
|
||||
if len(rangeEnd)%2 == 0 {
|
||||
return strconv.Atoi(rangeEnd[0 : len(rangeEnd)/2])
|
||||
} else {
|
||||
prefixLen := (len(rangeEnd) - 1) / 2
|
||||
return intPow(10, prefixLen) - 1, nil
|
||||
}
|
||||
}
|
||||
|
||||
func sumInt(seq []int) int {
|
||||
sum := 0
|
||||
|
||||
for _, val := range seq {
|
||||
sum += val
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
func getInvalidsForRange(start int, end int) []int {
|
||||
maxPrefix, err := largestPrefix(strconv.Itoa(end))
|
||||
check(err)
|
||||
|
||||
invalidIds := make(map[int]struct{})
|
||||
|
||||
fmt.Printf("Considering range %d - %d, max prefix %d\n", start, end, maxPrefix)
|
||||
for candidatePrefix := 1; candidatePrefix <= maxPrefix; candidatePrefix++ {
|
||||
for n_repeats := 2; ; n_repeats++ {
|
||||
candidateInt, err := makeCandidateInt(candidatePrefix, n_repeats)
|
||||
check(err)
|
||||
|
||||
if candidateInt > end {
|
||||
break
|
||||
}
|
||||
|
||||
if (start <= candidateInt) && (candidateInt <= end) {
|
||||
fmt.Printf("Can use %d\n", candidateInt)
|
||||
invalidIds[candidateInt] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
invalidIdList := make([]int, 0, len(invalidIds))
|
||||
|
||||
for invalidId := range invalidIds {
|
||||
invalidIdList = append(invalidIdList, invalidId)
|
||||
|
||||
}
|
||||
return invalidIdList
|
||||
}
|
||||
|
||||
func main() {
|
||||
file, err := os.Open("two.txt")
|
||||
check(err)
|
||||
defer file.Close()
|
||||
|
||||
invalidIdSum := 0
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
scanner.Split(scanComma)
|
||||
|
||||
for scanner.Scan() {
|
||||
idRange := scanner.Text()
|
||||
|
||||
idRangeSplit := strings.SplitN(idRange, "-", 2)
|
||||
|
||||
rangeStart, err := strconv.Atoi(idRangeSplit[0])
|
||||
check(err)
|
||||
rangeEnd, err := strconv.Atoi(idRangeSplit[1])
|
||||
check(err)
|
||||
|
||||
invalidIdSum += sumInt(getInvalidsForRange(rangeStart, rangeEnd))
|
||||
}
|
||||
fmt.Printf("%d\n", invalidIdSum)
|
||||
}
|
||||
72
2025/two/two_test.go
Normal file
72
2025/two/two_test.go
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package main
|
||||
|
||||
import "testing"
|
||||
|
||||
type invalidTest struct {
|
||||
arg1, arg2 int
|
||||
expected []int
|
||||
}
|
||||
|
||||
var invalidTests = []invalidTest{
|
||||
{11, 22, []int{11, 22}},
|
||||
{95, 115, []int{111, 99}},
|
||||
{998, 1012, []int{999, 1010}},
|
||||
{1188511880, 1188511890, []int{1188511885}},
|
||||
{222220, 222224, []int{222222}},
|
||||
{1698522, 1698528, []int{}},
|
||||
{446443, 446449, []int{446446}},
|
||||
{38593856, 38593862, []int{38593859}},
|
||||
{565653, 565659, []int{565656}},
|
||||
{824824821, 824824827, []int{824824824}},
|
||||
{2121212118, 2121212124, []int{2121212121}},
|
||||
}
|
||||
|
||||
func TestGetInvalids(t *testing.T) {
|
||||
for _, test := range invalidTests {
|
||||
out := getInvalidsForRange(test.arg1, test.arg2)
|
||||
|
||||
if len(out) != len(test.expected) {
|
||||
t.Errorf("Output %q not equal to expected %q", out, test.expected)
|
||||
}
|
||||
|
||||
for i, got := range out {
|
||||
want := test.expected[i]
|
||||
|
||||
if got != want {
|
||||
t.Errorf("Expected %d to be %d at position %d in %q", got, want, i, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntPow(t *testing.T) {
|
||||
val := intPow(10, 1)
|
||||
if val != 10 {
|
||||
t.Errorf("Was expecting 10, not %d", val)
|
||||
}
|
||||
|
||||
val = intPow(10, 2)
|
||||
if val != 100 {
|
||||
t.Errorf("Was expecting 100, not %d", val)
|
||||
}
|
||||
|
||||
val = intPow(10, 3)
|
||||
if val != 1000 {
|
||||
t.Errorf("Was expecting 1000, not %d", val)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestLargestPrefix(t *testing.T) {
|
||||
prefix, _ := largestPrefix("4444")
|
||||
|
||||
if prefix != 44 {
|
||||
t.Errorf("Should have return prefix 44, not %d", prefix)
|
||||
}
|
||||
|
||||
prefix, _ = largestPrefix("44444")
|
||||
|
||||
if prefix != 99 {
|
||||
t.Errorf("Should have returned prefix 99, not %d", prefix)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue