Optimize day 2, task 2 to only check relevant indexes to remove

This commit is contained in:
Markus Brueckner 2024-12-03 16:50:48 +01:00
parent b048f5c637
commit 93dbb551e4

View file

@ -10,22 +10,22 @@ fn read_input() -> Vec<Vec<i32>> {
.collect() .collect()
} }
fn is_safe(report: &Vec<i32>) -> bool { fn find_unsafe(report: &Vec<i32>) -> Option<usize> {
let mut last_value = report[0]; let mut last_value = report[0];
let mut increment = 0; let mut increment = 0;
// the current increment between two values. Mainly for tracking the direction of travel of the series // the current increment between two values. Mainly for tracking the direction of travel of the series
for current_value in report.iter().skip(1) { for (idx, current_value) in report.iter().enumerate().skip(1) {
let difference = current_value - last_value; let difference = current_value - last_value;
if increment * difference < 0 // i.e. difference & increment have different signs if increment * difference < 0 // i.e. difference & increment have different signs
|| difference.abs() < 1 || difference.abs() < 1
|| difference.abs() > 3 || difference.abs() > 3
{ {
return false; return Some(idx);
} }
last_value = *current_value; last_value = *current_value;
increment = difference; increment = difference;
} }
true None
} }
fn task1() { fn task1() {
@ -33,7 +33,7 @@ fn task1() {
let mut safe_reports = 0; let mut safe_reports = 0;
let mut unsafe_reports = 0; let mut unsafe_reports = 0;
for report in reports.iter() { for report in reports.iter() {
if is_safe(report) { if find_unsafe(report).is_none() {
safe_reports += 1; safe_reports += 1;
} else { } else {
unsafe_reports += 1; unsafe_reports += 1;
@ -54,25 +54,31 @@ fn task2() {
let mut unsafe_reports = 0; let mut unsafe_reports = 0;
let total = reports.len(); let total = reports.len();
for report in reports.into_iter() { for report in reports.into_iter() {
if is_safe(&report) { match find_unsafe(&report) {
safe_reports += 1; Some(idx) => {
} else { // got to check three cases here: removing the last item of the failed partial sequence, the one before or the one before that (to account for pattern
// check whether any value being left out makes it safe // like 3, 2, 3, 4, 5 at the start of a pattern, which becomes valid when removing index 0, but we'll only notice the issue at position 2)
let has_safe = 'safe_check: { let has_safe = 'safe_check: {
for ignore_idx in 0..report.len() { // make sure we don't actually access before the vector if the first gap is already invalie
for i in 0..std::cmp::min(3, idx + 1) {
// remove the potentially unsafe item check if that makes it safe
let mut modified_report = report.clone(); let mut modified_report = report.clone();
modified_report.splice(ignore_idx..ignore_idx + 1, []); modified_report.splice(idx - i..idx - i + 1, []);
if is_safe(&modified_report) { if find_unsafe(&modified_report).is_none() {
safe_reports += 1; // if there's one version how to make it safe, we're good safe_reports += 1;
break 'safe_check true; break 'safe_check true;
} }
} }
false // couldn't find a safe report false
}; };
if !has_safe { if !has_safe {
unsafe_reports += 1; unsafe_reports += 1;
} }
} }
None => {
safe_reports += 1;
}
}
} }
println!( println!(