DEV Community

Minindu Rupasinghe
Minindu Rupasinghe

Posted on

Advent of Code 2025 Day 2: Gift Shop 🎁

Me solving AoC day 2 problem

The Problem

We need to find "invalid" product IDs in given ranges. An ID is invalid if it's made of a repeated digit sequence.

Part 1: Find IDs repeated exactly twice (e.g., 1212, 345345)

Part 2: Find IDs repeated at least twice (e.g., 123123, 1111, 12121212)

Part 1: The Easy One

Part 1 was straightforward. For each number in the range:

  1. Convert to string
  2. Check if length is even
  3. Split in half and compare
fn invalid_id_sum1(ranges: Vec<(u128, u128)>) -> u128 {
    let mut id_sum: u128 = 0;
    for (start, end) in ranges.iter() {
        for i in *start..*end+1 {
            let s = i.to_string();
            if s.len() % 2 != 0 {
                continue;
            }
            let (a, b) = s.split_at(s.len() / 2);
            let x: u128 = a.parse().expect("Expected a number");
            let y: u128 = b.parse().expect("Expected a number");
            if x == y {
                id_sum += i;
            }
        }
    }
    id_sum
}
Enter fullscreen mode Exit fullscreen mode

Simple: if both halves match, it's invalid.

Part 2: The Tricky One

Part 2 got me thinking. Numbers can repeat 2, 3, 4+ times. My first approach only checked one specific split, which failed for cases like:

  • 12121212 (should be 1212|1212, not something else)
  • 12211221 (should be 1221|1221)

The fix: Try all possible split counts from 2 up to the maximum.

Here's my approach:

fn invalid_id_sum2(ranges: Vec<(u128, u128)>) -> u128 {
    let mut id_sum: u128 = 0;
    for (start, end) in ranges.iter() {
        for i in *start..*end+1 {
            let s = i.to_string();
            let mut map: [usize; 10] = [0; 10];
            for c in s.chars() {
                if let Some(digit) = c.to_digit(10) {
                    map[digit as usize] += 1;
                }
            }
            let mut splits: usize= 1000;

            for j in 0..10 {
                if map[j] != 0 {
                    splits = min(splits, map[j]);
                }
            }
            for split in 2..splits+1 {
                let len = s.len() / split ;
                let mut parts: Vec<i128> = Vec::new();
                let mut start = 0;

                for _ in 0..split {
                    let end = start + len;
                    parts.push((&s[start..end]).parse().expect("Expected a number"));
                    start = end;
                }
                if start < s.len() {
                    parts.push((&s[start..]).parse().expect("Expected a number"));
                }
                let num = parts[0];
                let mut invalid = true;
                for x in 1..parts.len() {
                    if num != parts[x] {
                        invalid = false;
                    }
                }
                if parts.len() == 1 {
                    invalid = false;
                }
                if invalid {
                    id_sum += i;
                    break
                }
            }
        }
    }
    id_sum
}
Enter fullscreen mode Exit fullscreen mode

The key insight: digit frequency gives us the upper bound for splits, but we need to try all valid split counts starting from 2.

Lessons Learned

Sometimes the brute force approach needs a bit of finesse. Don't just check one split pattern; check them all within reasonable bounds.


Full code available on my GitHub ⭐

Top comments (0)