Red-Nosed Reports: Advent of Code 2024 (Day 2)
Welcome back to Advent of Code 2024, Day 2! This challenge felt relatively easy, as it taught two fundamental programming concepts: traversing arrays and working with conditions.
You can find the puzzle for the story here. It involves helping engineers at the Red-Nosed reactor analyze reports to determine which ones are “safe.” Let’s dive into the problem and explore how I solved it.
You can find the working code in my GitHub.
Process the data
The input for this problem consists of several reports, where each report is a space-separated array of integers. First, we need to load this data into a structured format. Here’s the code to store the reports as a vector of integer vectors (data
):
vector<vector<int> > data;
void loadData() {
string line;
ifstream ip("ip.txt");
if (ip.is_open()) {
while (getline(ip, line)) {
string level;
vector<int> report;
stringstream ss(line);
while (getline(ss, level, ' ')) {
report.push_back(stoi(level));
}
data.push_back(report);
}
ip.close();
}
}
Key Syntax:
getline(string stream, variable, delimiter)
reads a line or splits it based on the delimiter. Here, it helps split numbers separated by spaces.
Part 1: Counting Safe Reports
In the first part of the puzzle, we determine how many reports are “safe.” A report is considered safe if:
- The levels in the array are either strictly increasing or strictly decreasing
- The difference between any two adjacent levels is at least 1 and at most 3
My Approach:
To check these conditions, I wrote an isSafe()
function:
bool isSafe(vector<int> arr) {
int n = arr.size();
bool isIncreasing = true;
bool isDecreasing = true;
for (int i = 0; i < n - 1; i++) {
if (arr[i] >= arr[i + 1]) {
isIncreasing = false;
}
if (arr[i] <= arr[i + 1]) {
isDecreasing = false;
}
if (abs(arr[i] - arr[i + 1]) > 3) {
return false;
}
}
return isIncreasing || isDecreasing;
}
How It Works:
- Start by assuming the array could be increasing or decreasing
- Loop through the array and update these flags based on the values of adjacent elements
- If the difference between any two adjacent elements exceeds 3, return
false
immediately
Finally, loop through all the reports to count the safe ones:
int main() {
loadData();
int cnt = 0;
for (int i = 0; i < data.size(); i++) {
if (isSafe(data[i])) {
cnt++;
}
}
cout << "total safe reports: " << cnt;
return 0;
}
Part 2: Adding a New Rule
Part 2 introduces an extra challenge. Now, the updated safety criteria will be:
3. If removing one element from an array makes it monotonic, it is also considered safe.
My Approach:
For this, I wrote a canBeSafe()
function:
bool canBeSafe(vector<int> arr) {
int n = arr.size();
for (int i = 0; i < n; i++) {
vector<int> temp = arr;
temp.erase(temp.begin() + i);
if (isSafe(temp)) {
return true;
}
}
return false;
}
Here, we first check if a report is safe as per Part 1’s rules. If not, we use the canBeSafe()
function to check if it can be made safe by removing one level.
Finally, combine the logic for both parts to count the total safe reports:
int main() {
loadData();
int cnt = 0;
for (int i = 0; i < data.size(); i++) {
if (isSafe(data[i])) { // part - 1
cnt++;
} else if (canBeSafe(data[i])) { // part - 2
cnt++;
}
}
cout << "total safe reports: " << cnt;
return 0;
}
While this solution works, I feel the two functions (isSafe
and canBeSafe
) could be optimized and merged. However, with my current knowledge, I couldn’t find a way to elegantly combine them without making the code messy.
Conclusion
This question is a great exercise in array manipulation and logical thinking. It reinforces concepts like:
- Traversing arrays
- Implementing multiple conditions
- Using helper functions to simplify logic
If you enjoyed solving this, check out these related LeetCode problems:
- 896. Monotonic Array
- 1909. Remove One Element to Make the Array Strictly Increasing
- 3250. Find the Count of Monotonic Pairs I (similar concept, yet to be solved by me!)