🎄

Advent of Code 2020 day06

2020/12/13に公開

https://adventofcode.com/2020/day/6

part1

abc

a
b
c

ab
ac

a
a
a
a

b

のような、day04と同様な空行で区切られたgroupがあり、各行がその同一group内で各人が"yes"と回答した質問を表す。

part1は、各groupで"yes"と回答された質問の数をかぞえ、合計を出せ、という問題。単純に各group内で出現するuniqueな文字数をカウントして合計すれば良いだけ。
aからzまでというのは分かっているので辞書にはHashSetなどを使う必要もなく、26 sizeのbool配列だけ用意すれば良い。

struct Solution {
    inputs: Vec<String>,
}

impl Solution {
    fn new(inputs: Vec<String>) -> Self {
        Self { inputs }
    }
    fn solve_1(&self) -> usize {
        let mut ret = 0;
        let mut d = [false; 26];
        for line in self.inputs.iter().chain([String::new()].iter()) {
            if line.is_empty() {
                for b in d.iter_mut() {
                    if *b {
                        ret += 1;
                    }
                    *b = false;
                }
            } else {
                for &b in line.as_bytes() {
                    d[(b - b'a') as usize] = true;
                }
            }
        }
        ret
    }
}

part2

実はかぞえるべきは「groupの誰かが"yes"と回答した」ではなく「groupの全員が"yes"と回答した」質問の数だった、という。
bool演算でいうと OR で見ていたのが AND で見る必要があった、ということになる。
せっかくなので、bool配列で管理していたものを u32の各bitで管理するように変更してみた。各人の回答をu32の値に変換して持ち、part1は | で、part2は & でgroup内全員の値をfoldしていけばあとは最終的な値のbit countを調べるだけで良くなる。 & の場合は初期値が全部立っている必要があるので注意。

struct Solution {
    groups: Vec<Vec<u32>>,
}

impl Solution {
    fn new(inputs: Vec<String>) -> Self {
        let mut groups: Vec<Vec<u32>> = Vec::new();
        let mut v: Vec<u32> = Vec::new();
        for line in inputs.iter().chain([String::new()].iter()) {
            if line.is_empty() {
                groups.push(v.clone());
                v.clear();
            } else {
                v.push(
                    line.as_bytes()
                        .iter()
                        .map(|&b| 1 << (b - b'a') as usize)
                        .fold(0, |acc, x| acc | x),
                );
            }
        }
        Self { groups }
    }
    fn solve_1(&self) -> usize {
        self.groups
            .iter()
            .map(|group| group.iter().fold(0, |acc, &x| acc | x).count_ones() as usize)
            .sum()
    }
    fn solve_2(&self) -> usize {
        self.groups
            .iter()
            .map(|group| {
                group
                    .iter()
                    .fold((1 << 26) - 1, |acc, &x| acc & x)
                    .count_ones() as usize
            })
            .sum()
    }
}

Discussion