questions B (backspace - burst-balloons)

This commit is contained in:
2025-05-24 22:06:49 +01:00
parent f757e28b24
commit 2123791ec3
67 changed files with 13945 additions and 0 deletions

View File

@@ -0,0 +1,199 @@
title: Baseball Game
slug: baseball-game
difficulty: easy
leetcode_id: 682
leetcode_url: https://leetcode.com/problems/baseball-game/
categories:
- arrays
- stack
patterns:
- monotonic-stack
description: |
You are keeping the scores for a baseball game with strange rules. At the beginning of the game, you start with an empty record.
You are given a list of strings `operations`, where `operations[i]` is the i<sup>th</sup> operation you must apply to the record and is one of the following:
- An integer `x` — Record a new score of `x`.
- `'+'` — Record a new score that is the sum of the previous two scores.
- `'D'` — Record a new score that is the double of the previous score.
- `'C'` — Invalidate the previous score, removing it from the record.
Return *the sum of all the scores on the record after applying all the operations*.
The test cases are generated such that the answer and all intermediate calculations fit in a **32-bit** integer and that all operations are valid.
constraints: |
- `1 <= operations.length <= 1000`
- `operations[i]` is `"C"`, `"D"`, `"+"`, or a string representing an integer in the range `[-3 * 10^4, 3 * 10^4]`
- For operation `"+"`, there will always be at least two previous scores on the record
- For operations `"C"` and `"D"`, there will always be at least one previous score on the record
examples:
- input: 'ops = ["5","2","C","D","+"]'
output: "30"
explanation: |
"5" - Add 5 to the record, record is now [5].
"2" - Add 2 to the record, record is now [5, 2].
"C" - Invalidate and remove the previous score, record is now [5].
"D" - Add 2 * 5 = 10 to the record, record is now [5, 10].
"+" - Add 5 + 10 = 15 to the record, record is now [5, 10, 15].
The total sum is 5 + 10 + 15 = 30.
- input: 'ops = ["5","-2","4","C","D","9","+","+"]'
output: "27"
explanation: |
"5" - Add 5 to the record, record is now [5].
"-2" - Add -2 to the record, record is now [5, -2].
"4" - Add 4 to the record, record is now [5, -2, 4].
"C" - Invalidate and remove the previous score, record is now [5, -2].
"D" - Add 2 * -2 = -4 to the record, record is now [5, -2, -4].
"9" - Add 9 to the record, record is now [5, -2, -4, 9].
"+" - Add -4 + 9 = 5 to the record, record is now [5, -2, -4, 9, 5].
"+" - Add 9 + 5 = 14 to the record, record is now [5, -2, -4, 9, 5, 14].
The total sum is 5 + -2 + -4 + 9 + 5 + 14 = 27.
- input: 'ops = ["1","C"]'
output: "0"
explanation: |
"1" - Add 1 to the record, record is now [1].
"C" - Invalidate and remove the previous score, record is now [].
Since the record is empty, the total sum is 0.
explanation:
intuition: |
Imagine you're keeping score on a notepad where you can only add entries at the bottom and erase the most recent entry. This is exactly how a **stack** works — Last In, First Out (LIFO).
The key insight is that every operation either:
- **Adds** a new score to the end of the record (integer, `+`, `D`)
- **Removes** the most recent score (`C`)
This matches perfectly with stack operations: `push` to add and `pop` to remove. The stack always maintains the current valid scores in order, so we can easily access the last one or two elements when needed.
Think of it like this: the record is a stack of paper slips. When you get a new score, you place a slip on top. When you need to double (`D`) or sum (`+`), you peek at the top slip(s), calculate, and add a new slip. When you invalidate (`C`), you simply remove the top slip.
approach: |
We solve this using a **Stack Simulation** approach:
**Step 1: Initialise an empty stack**
- `record`: An empty list to act as our stack, storing valid scores
&nbsp;
**Step 2: Process each operation**
- For each operation in the input:
- If it's an **integer**: Convert to int and push onto the stack
- If it's `"+"`: Add the sum of the last two scores (`record[-1] + record[-2]`) to the stack
- If it's `"D"`: Add double the last score (`2 * record[-1]`) to the stack
- If it's `"C"`: Pop the last score from the stack
&nbsp;
**Step 3: Return the sum**
- Return `sum(record)` — the sum of all remaining valid scores
&nbsp;
The stack naturally maintains only the valid scores at any point. Since the problem guarantees all operations are valid (e.g., `+` always has at least two previous scores), we don't need additional boundary checks.
common_pitfalls:
- title: Not Recognising the Stack Pattern
description: |
Some developers try to use complex conditionals or maintain separate variables instead of recognising this as a classic stack problem.
The operations map directly to stack operations:
- Integer → `push(value)`
- `"+"` → `push(peek(-1) + peek(-2))`
- `"D"` → `push(2 * peek(-1))`
- `"C"` → `pop()`
Once you see this mapping, the solution becomes straightforward.
wrong_approach: "Complex state tracking with multiple variables"
correct_approach: "Use a stack to track the record"
- title: Integer Parsing Edge Cases
description: |
Remember that scores can be **negative** (e.g., `"-2"`). When checking if an operation is an integer, don't just check if the first character is a digit — it could be a minus sign.
In Python, using `try/except` with `int()` or checking with `lstrip('-').isdigit()` handles this correctly. Alternatively, check if the operation is not one of the three special characters.
wrong_approach: "Checking only if first char is digit"
correct_approach: "Check if operation is not in {'C', 'D', '+'}"
- title: Off-by-One in Index Access
description: |
When accessing the last two elements for the `"+"` operation, remember:
- `record[-1]` is the most recent (last) score
- `record[-2]` is the second-to-last score
The problem guarantees at least two scores exist for `"+"`, so this access is always safe.
key_takeaways:
- "**Stack pattern recognition**: When operations involve 'most recent' or 'undo', think stack"
- "**Simulation problems**: Walk through the operations step-by-step, maintaining state as you go"
- "**Python negative indexing**: `list[-1]` and `list[-2]` provide clean access to recent elements"
- "**Trust the constraints**: When the problem guarantees valid operations, you can skip defensive checks"
time_complexity: "O(n). We process each operation exactly once, where `n` is the length of `operations`."
space_complexity: "O(n). In the worst case, all operations are integers, so the stack stores `n` elements."
solutions:
- approach_name: Stack Simulation
is_optimal: true
code: |
def cal_points(operations: list[str]) -> int:
# Stack to track valid scores
record = []
for op in operations:
if op == '+':
# Sum of the last two scores
record.append(record[-1] + record[-2])
elif op == 'D':
# Double the last score
record.append(2 * record[-1])
elif op == 'C':
# Remove the last score
record.pop()
else:
# It's an integer score
record.append(int(op))
# Return sum of all valid scores
return sum(record)
explanation: |
**Time Complexity:** O(n) — Single pass through operations, each operation is O(1).
**Space Complexity:** O(n) — Stack can grow to size n in the worst case.
We simulate the game by processing each operation and maintaining a stack of valid scores. The stack's LIFO property perfectly matches the problem's requirement to access and modify the most recent scores.
- approach_name: Stack with Running Sum
is_optimal: false
code: |
def cal_points(operations: list[str]) -> int:
record = []
total = 0
for op in operations:
if op == '+':
score = record[-1] + record[-2]
elif op == 'D':
score = 2 * record[-1]
elif op == 'C':
# Subtract the removed score from total
total -= record.pop()
continue
else:
score = int(op)
record.append(score)
total += score
return total
explanation: |
**Time Complexity:** O(n) — Single pass through operations.
**Space Complexity:** O(n) — Same stack storage.
This variation maintains a running total, adding scores as they're pushed and subtracting when popped. While it avoids calling `sum()` at the end, the overall complexity is the same. The first approach is cleaner and preferred.