Advent of Code 2020 day05
part1
FBFBBFFRLR
のように F
or B
からなる7文字に続いて L
or R
からなる3文字が続く文字列が与えられる。前半7文字で128
rowsのうちどれか、後半3文字で8
columnsのうちどれか、をそれぞれ二分探索のような操作で表すことになるのだけど、これは問題をよく読んでちょっと考えると単純に2進数に変換できることに気付く。
F
と L
を 0
、 B
と R
を 1
としてそれぞれ扱う。FBFBBFF
は 0b0101100
なので 44
に、 RLR
は 0b101
なので 5
になる。
そして求めるべき seat ID は row * 8 + column
なのでこれはそのまま繋げて2進数として扱うだけで良い。 FBFBBFFRLR
がそのまま 0b0101100101
で 357
になる。
part1 は seat ID の最大値を求める、とのことなので 単純に全入力を変換した上で max
を求めれば良いだけ。
struct Solution {
inputs: Vec<String>,
}
impl Solution {
fn new(inputs: Vec<String>) -> Self {
Self { inputs }
}
fn solve_1(&self) -> i32 {
self.inputs
.iter()
.map(|seat| {
seat.chars()
.rev()
.enumerate()
.map(|(i, c)| if matches!(c, 'B' | 'R') { 1 << i } else { 0 })
.sum()
})
.max()
.unwrap()
}
}
part2
求める seat ID は入力列の中に存在していないIDである、とのこと。ただし実際に有り得る 0
から 1023
までのうち小さい方や大きい方のIDはそもそも存在していない。
全IDをsortして順番に見ていって抜けているIDを探しても良いけど、
問題にある通り、 0
から 1023
までのうちのどこかの区間でほぼ連続になっているはず、なので、「part1で求めた最大値」と「入力の行数」から全seat IDがどの範囲にあるはずなのかは見当がつく。例えばpart1で求めた最大値が 900
で、入力が全部で 800
行あったとしたら、 100
が最小値で入力はすべて 100
と 900
の間のどれか、になることが分かる。その 801
個の候補のうち 1つだけ存在していない数値があるはず。なので入力数+1の領域だけbool
を入れる配列を確保して存在確認だけしていけば良い。これなら
struct Solution {
seats: Vec<i32>,
}
impl Solution {
fn new(inputs: Vec<String>) -> Self {
Self {
seats: inputs
.iter()
.map(|seat| {
seat.chars()
.rev()
.enumerate()
.map(|(i, c)| if matches!(c, 'B' | 'R') { 1 << i } else { 0 })
.sum()
})
.collect(),
}
}
fn solve_1(&self) -> i32 {
*self.seats.iter().max().unwrap()
}
fn solve_2(&self) -> i32 {
let offset = self.solve_1() as usize - self.seats.len();
let mut v = vec![false; self.seats.len() + 1];
for &seat in self.seats.iter() {
v[seat as usize - offset] = true;
}
(v.iter().position(|&b| !b).unwrap() + offset) as i32
}
}
Discussion