Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ scripts/__pycache__/
descriptions/
.venv/
__pycache__/
node_modules/
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npm run format:json
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Missing shebang line will prevent hook execution.

Git hooks require a shebang line (e.g., #!/bin/sh or #!/usr/bin/env bash) as the first line to specify the interpreter. Without it, the hook may fail to execute or behave unpredictably.

Apply this diff to add the shebang:

+#!/bin/sh
 npm run format:json
 git add 'data/**/*.json'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
npm run format:json
#!/bin/sh
npm run format:json
🤖 Prompt for AI Agents
.husky/pre-commit around lines 1-1: the hook is missing a shebang so the
interpreter is undefined and the hook may not run; add a shebang as the very
first line (for example use /usr/bin/env bash or /bin/sh) so the hook runs with
a defined shell, leaving the existing npm run format:json line intact and ensure
the file remains executable.

225 changes: 224 additions & 1 deletion data/book-sets.json

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions explanations/3178/en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
## Explanation

### Strategy (The "Why")

**Restate the problem:** We have n children numbered 0 to n-1 standing in a line. Child 0 initially holds a ball and passes it right. When the ball reaches either end (child 0 or child n-1), the direction reverses. We need to find which child has the ball after k seconds.

**1.1 Constraints & Complexity:**

- **Input Size:** n is between 2 and 50, k is between 1 and 50. These are small values, so simulation is feasible.
- **Time Complexity:** O(k mod period) where period = 2*(n-1). Since k and n are small, this is effectively O(k) in worst case.
- **Space Complexity:** O(1) - we only use a few variables to track position and direction.
- **Edge Case:** When n=2, the period is 2, so the ball alternates between children 0 and 1.

**1.2 High-level approach:**

The goal is to simulate the ball passing pattern. The key insight is that the pattern repeats every 2*(n-1) seconds, so we can use modulo arithmetic to reduce k before simulation.

**1.3 Brute force vs. optimized strategy:**

- **Brute Force:** Simulate all k seconds step by step. This is O(k) time.
- **Optimized Strategy:** Recognize that the pattern repeats every 2*(n-1) seconds. Use k % (2*(n-1)) to reduce the simulation time. This is still O(k) in worst case but more efficient for large k values.
- **Optimization:** By using modulo, we avoid simulating redundant cycles when k is much larger than the period.

**1.4 Decomposition:**

1. Calculate the period of repetition: 2 * (n - 1) seconds.
2. Reduce k using modulo: k_mod = k % period.
3. Initialize position at 0 and direction as 1 (right).
4. Simulate k_mod steps: move position by direction, reverse direction at boundaries.
5. Return the final position.

### Steps (The "How")

**2.1 Initialization & Example Setup:**

Let's use the example input: `n = 3`, `k = 5`.

- Period = 2 * (3 - 1) = 2 * 2 = 4
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix markdown formatting.

Line 38 has spaces inside emphasis markers. Remove the spaces for proper markdown formatting.

Expected format:

- Period = 2 * (3 - 1) = 2 * 2 = 4
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

38-38: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)


38-38: Spaces inside emphasis markers

(MD037, no-space-in-emphasis)

🤖 Prompt for AI Agents
In explanations/3178/en.md around line 38, the markdown uses emphasis markers
with spaces inside them; remove the spaces immediately inside the asterisks or
underscores so the line reads a properly formatted list item (e.g., "- Period =
2 * (3 - 1) = 2 * 2 = 4") ensuring no spaces between the marker and the text.

- k_mod = 5 % 4 = 1
- Initial position = 0, direction = 1 (right)

**2.2 Start Simulation:**

We simulate k_mod = 1 step.

**2.3 Trace Walkthrough:**

| Step | Position | Direction | Action |
|------|----------|-----------|--------|
| 0 | 0 | 1 (right) | Start at child 0 |
| 1 | 1 | 1 (right) | Move right to child 1 |

**2.4 Increment and Loop:**

After k_mod steps, we have the final position.

**2.5 Return Result:**

The final position is 1, so child 1 has the ball after k=5 seconds. This matches the example where after 5 seconds, the ball is at child 1.

60 changes: 60 additions & 0 deletions explanations/3179/en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
## Explanation

### Strategy (The "Why")

**Restate the problem:** We start with an array of n integers, all set to 1. After each second, we update each element to be the sum of all its preceding elements plus the element itself. We need to find the value at index n-1 after k seconds.

**1.1 Constraints & Complexity:**

- **Input Size:** n and k are both between 1 and 1000. The values can grow very large, so we need modulo 10^9 + 7.
- **Time Complexity:** O(n \* k) - we iterate k times, and for each iteration, we process n-1 elements.
- **Space Complexity:** O(n) - we maintain an array of size n.
- **Edge Case:** When k=0, the array remains [1,1,...,1], so the result is 1.

**1.2 High-level approach:**

The goal is to apply prefix sum operation k times. Each second, we compute the prefix sum of the current array, which becomes the new array for the next second.

**1.3 Brute force vs. optimized strategy:**

- **Brute Force:** Simulate k seconds by computing prefix sums k times. This is O(n \* k) time and O(n) space.
- **Optimized Strategy:** The same approach is already optimal. We can't avoid computing each prefix sum operation.
- **Optimization:** Using modulo arithmetic ensures we don't overflow, and the direct simulation is the most straightforward approach.

**1.4 Decomposition:**

1. Initialize an array of n elements, all set to 1.
2. For k iterations, compute the prefix sum of the current array.
3. Apply modulo 10^9 + 7 to prevent overflow.
4. Return the value at index n-1.

### Steps (The "How")

**2.1 Initialization & Example Setup:**

Let's use the example input: `n = 4`, `k = 5`.

- Initial array: `[1, 1, 1, 1]`

**2.2 Start Processing:**

We apply prefix sum k=5 times.

**2.3 Trace Walkthrough:**

| Second | Array State | Action |
| ------ | -------------- | ----------------------------------------------------------- |
| 0 | [1, 1, 1, 1] | Initial state |
| 1 | [1, 2, 3, 4] | Prefix sum: arr[1]=1+1=2, arr[2]=1+2=3, arr[3]=1+2+3=4 |
| 2 | [1, 3, 6, 10] | Prefix sum: arr[1]=1+2=3, arr[2]=1+3+2=6, arr[3]=1+3+6=10 |
| 3 | [1, 4, 10, 20] | Prefix sum: arr[1]=1+3=4, arr[2]=1+4+3=10, arr[3]=1+4+10=20 |
| 4 | [1, 5, 15, 35] | Prefix sum: arr[1]=1+4=5, arr[2]=1+5+4=15, arr[3]=1+5+15=35 |
| 5 | [1, 6, 21, 56] | Prefix sum: arr[1]=1+5=6, arr[2]=1+6+5=21, arr[3]=1+6+21=56 |

**2.4 Increment and Loop:**

After k iterations, we have the final array state.

**2.5 Return Result:**

The value at index n-1 (index 3) after k=5 seconds is 56, which matches the example output.
62 changes: 62 additions & 0 deletions explanations/3212/en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
## Explanation

### Strategy (The "Why")

**Restate the problem:** We are given a 2D character matrix where each cell contains 'X', 'Y', or '.'. We need to count submatrices that start at (0,0), contain equal frequency of 'X' and 'Y', and have at least one 'X'.

**1.1 Constraints & Complexity:**

- **Input Size:** Grid dimensions can be up to 1000x1000. We need an efficient approach.
- **Time Complexity:** O(m * n * min(m,n)) - we check all submatrices starting from (0,0), and for each, we check if it contains at least one X, which takes O(m*n) in worst case.
- **Space Complexity:** O(m * n) for the prefix sum matrix.
- **Edge Case:** If the grid has no 'X', the result is 0.

**1.2 High-level approach:**

The goal is to use prefix sums to efficiently calculate the sum of any submatrix. We convert 'X' to 1, 'Y' to -1, and '.' to 0. A submatrix with sum 0 has equal frequency of X and Y.

**1.3 Brute force vs. optimized strategy:**

- **Brute Force:** For each submatrix, count X and Y by iterating through all cells. This is O(m^2 * n^2) time.
- **Optimized Strategy:** Use prefix sum to calculate submatrix sum in O(1) time. Check all submatrices starting from (0,0) and verify they contain at least one X. This is O(m * n * min(m,n)) time.
- **Optimization:** Prefix sum allows us to compute submatrix sums efficiently, reducing the time complexity significantly.

**1.4 Decomposition:**

1. Convert characters to numeric values: X=1, Y=-1, .=0.
2. Build a prefix sum matrix for efficient submatrix sum calculation.
3. For each submatrix starting from (0,0), check if it contains at least one X.
4. If it does and the sum is 0 (equal X and Y), increment the result.

### Steps (The "How")

**2.1 Initialization & Example Setup:**

Let's use the example input: `grid = [["X","Y","."],["Y",".","."]]`

- Convert to numeric: X=1, Y=-1, .=0
- Build prefix sum matrix

**2.2 Start Checking:**

We iterate through all possible submatrices starting from (0,0).

**2.3 Trace Walkthrough:**

| Submatrix | Prefix Sum | Has X? | Sum = 0? | Count |
|-----------|------------|--------|----------|-------|
| (0,0) to (0,0) | 1 | Yes | No | 0 |
| (0,0) to (0,1) | 1 + (-1) = 0 | Yes | Yes | 1 |
| (0,0) to (0,2) | 0 + 0 = 0 | Yes | Yes | 2 |
| (0,0) to (1,0) | 1 + (-1) = 0 | Yes | Yes | 3 |
| (0,0) to (1,1) | 1 + (-1) + (-1) + 0 = -1 | Yes | No | 3 |
| (0,0) to (1,2) | -1 + 0 = -1 | Yes | No | 3 |

**2.4 Increment and Loop:**

We continue checking all submatrices and count those that meet the criteria.

**2.5 Return Result:**

The result is 3, which matches the example output. The three valid submatrices are: (0,0)-(0,1), (0,0)-(0,2), and (0,0)-(1,0).

59 changes: 59 additions & 0 deletions explanations/3244/en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
## Explanation

### Strategy (The "Why")

**Restate the problem:** We have n cities in a line, with initial roads from city i to i+1. We process queries that add new roads, and after each query, we need to find the shortest path length from city 0 to city n-1.

**1.1 Constraints & Complexity:**

- **Input Size:** n can be up to 10^5, and there can be up to 10^5 queries. We need an efficient O(n + q) solution.
- **Time Complexity:** O(n + q) - we initialize the linked list in O(n) and process each query in O(1) amortized time.
- **Space Complexity:** O(n) - we maintain a dictionary representing the linked list structure.
- **Edge Case:** When n=2, there's only one edge, so the path length is always 1.

**1.2 High-level approach:**

The goal is to model the graph as a linked list. Initially, each city i points to i+1. When we add a road from i to j, we remove all intermediate nodes and create a direct link. The shortest path length equals the number of edges in the linked list.

**1.3 Brute force vs. optimized strategy:**

- **Brute Force:** After each query, run BFS to find shortest path. This is O(q * n) time.
- **Optimized Strategy:** Model as a linked list and maintain it efficiently. When adding edge (i,j), remove nodes between i and j. The path length is the size of the dictionary. This is O(n + q) time.
- **Optimization:** The linked list approach avoids repeated graph traversals and allows us to update the path structure efficiently.

**1.4 Decomposition:**

1. Initialize a dictionary d where d[i] = i+1 for all i from 0 to n-2 (linked list structure).
2. For each query (i, j), if d[i] < j, remove all nodes between i and j, then set d[i] = j.
3. The shortest path length is the number of edges, which equals len(d).
4. Return the path length after each query.

### Steps (The "How")

**2.1 Initialization & Example Setup:**

Let's use the example input: `n = 5`, `queries = [[2,4],[0,2],[0,4]]`

- Initial dictionary: `{0: 1, 1: 2, 2: 3, 3: 4}`
- Initial path length: 4 (edges: 0→1, 1→2, 2→3, 3→4)

**2.2 Start Processing:**

We process each query and update the linked list.

**2.3 Trace Walkthrough:**

| Query | Dictionary Before | Action | Dictionary After | Path Length |
|-------|-------------------|--------|------------------|-------------|
| [2,4] | {0:1, 1:2, 2:3, 3:4} | Remove node 3, set d[2]=4 | {0:1, 1:2, 2:4} | 3 |
| [0,2] | {0:1, 1:2, 2:4} | Remove node 1, set d[0]=2 | {0:2, 2:4} | 2 |
| [0,4] | {0:2, 2:4} | Remove node 2, set d[0]=4 | {0:4} | 1 |

**2.4 Increment and Loop:**

After processing all queries, we have the final path lengths.

**2.5 Return Result:**

The result is [3, 2, 1], which matches the example output. The path lengths decrease as we add shortcuts that bypass intermediate cities.

61 changes: 61 additions & 0 deletions explanations/3276/en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
## Explanation

### Strategy (The "Why")

**Restate the problem:** We need to select one or more cells from a grid such that no two selected cells are in the same row, and all selected values are unique. We want to maximize the sum of selected cell values.

**1.1 Constraints & Complexity:**

- **Input Size:** Grid dimensions are at most 10x10, and values are between 1 and 100. The small size allows for exponential solutions.
- **Time Complexity:** O(V * R^V) where V is the number of unique values and R is the number of rows. With memoization, this is more efficient in practice.
- **Space Complexity:** O(V * 2^R) for memoization - we store states based on which rows are used and which values we've processed.
- **Edge Case:** If all values in a row are the same, we can only select one value from that row.

**1.2 High-level approach:**

The goal is to use dynamic programming with memoization. We process values in descending order (greedy approach), and for each value, we decide which row to select it from (if any), ensuring we don't violate constraints.

**1.3 Brute force vs. optimized strategy:**

- **Brute Force:** Try all combinations of cells, checking constraints. This is exponential and inefficient.
- **Optimized Strategy:** Use DFS with memoization, processing values in descending order. Track which rows have been used and which values we've processed. This reduces redundant computations significantly.
- **Optimization:** Memoization based on (row_set, value_idx) avoids recomputing the same subproblems, and processing in descending order ensures we consider optimal choices first.

**1.4 Decomposition:**

1. Collect all unique values from the grid and sort them in descending order.
2. Create a mapping from each value to the list of rows containing it.
3. Use DFS with memoization: for each value, try selecting it from each available row, or skip it.
4. Track used rows to ensure no two cells from the same row are selected.
5. Return the maximum score achievable.

### Steps (The "How")

**2.1 Initialization & Example Setup:**

Let's use the example input: `grid = [[1,2,3],[4,3,2],[1,1,1]]`

- Unique values (descending): [4, 3, 2, 1]
- Value to rows mapping: {4: [1], 3: [0,1], 2: [0,1], 1: [0,2]}

**2.2 Start DFS:**

We process values in descending order, making optimal choices.

**2.3 Trace Walkthrough:**

| Value | Available Rows | Decision | Used Rows | Score |
|-------|----------------|----------|-----------|-------|
| 4 | [1] | Select from row 1 | {1} | 4 |
| 3 | [0,1] | Row 1 used, select from row 0 | {0,1} | 4+3=7 |
| 2 | [0,1] | Both rows used, skip | {0,1} | 7 |
| 1 | [0,2] | Row 0 used, select from row 2 | {0,1,2} | 7+1=8 |

**2.4 Increment and Loop:**

The DFS explores all possibilities and returns the maximum score.

**2.5 Return Result:**

The maximum score is 8, achieved by selecting values 4 (row 1), 3 (row 0), and 1 (row 2). This matches the example output.

75 changes: 75 additions & 0 deletions explanations/3573/en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
## Explanation

### Strategy (The "Why")

**Restate the problem:** We are given stock prices for each day and allowed to make at most k transactions. Each transaction can be either a normal transaction (buy then sell) or a short selling transaction (sell then buy back). We must find the maximum profit we can earn.

**1.1 Constraints & Complexity:**

- **Input Size:** We have at most 1000 days (prices.length <= 10^3), and each price is between 1 and 10^9. We can make at most k transactions where k <= prices.length / 2.
- **Time Complexity:** O(n * k) where n is the number of days and k is the maximum number of transactions. We iterate through each day and for each day, we process all k transactions.
- **Space Complexity:** O(k) for storing the DP arrays (res, bought, sold) of size k.
- **Edge Case:** If k is 0, we cannot make any transactions, so the profit is 0.

**1.2 High-level approach:**

The goal is to maximize profit by choosing the best sequence of transactions (normal or short selling) up to k transactions. We use dynamic programming to track the best profit at each stage of transaction completion.

**1.3 Brute force vs. optimized strategy:**

- **Brute Force:** Try all possible combinations of transactions (normal or short) at each day, which would be exponential in complexity O(2^(n*k)).
Comment on lines +11 to +20
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Clarify the described sizes of the DP arrays to match the example initialization.

The example initializes res with k+1 entries (for 0..k completed transactions), while bought and sold have length k. Please adjust the description so it matches this (e.g., explicitly call out res as size k+1 and bought/sold as size k).

- **Optimized Strategy:** Use dynamic programming with three state arrays: `res[j]` tracks best profit after completing j transactions, `bought[j]` tracks best profit when holding a bought position in the j-th transaction, and `sold[j]` tracks best profit when holding a short position in the j-th transaction. This is O(n * k) time and O(k) space.
- **Optimization:** By maintaining separate states for bought and sold positions, we can efficiently track and update the maximum profit at each stage without recalculating all possibilities.

**1.4 Decomposition:**

1. Initialize three arrays: `res` (completed transactions), `bought` (holding bought positions), and `sold` (holding short positions).
2. For each day's price, process transactions from k down to 1 (to avoid using updated values).
3. For each transaction count j, update `res[j]` by completing either a normal transaction (sell) or short transaction (buy back).
4. Update `bought[j-1]` by starting a new normal transaction (buy at current price).
5. Update `sold[j-1]` by starting a new short transaction (sell at current price).
6. Return the maximum value in `res` array.

### Steps (The "How")

**2.1 Initialization & Example Setup:**

Let's use the example input: `prices = [1, 7, 9, 8, 2]`, `k = 2`.

- Initialize `res = [0, 0, 0]` (profit after 0, 1, or 2 completed transactions)
- Initialize `bought = [-inf, -inf]` (best profit when holding bought position in transaction 0 or 1)
- Initialize `sold = [0, 0]` (best profit when holding short position in transaction 0 or 1)

**2.2 Start Processing:**

We iterate through each price in the array, updating our DP states.

**2.3 Trace Walkthrough:**

| Day | Price | Transaction | Action | res | bought | sold |
|-----|-------|-------------|--------|-----|--------|------|
| 0 | 1 | j=2 | Start normal: bought[1] = max(-inf, res[1] - 1) = max(-inf, 0 - 1) = -1 | [0,0,0] | [-inf,-1] | [0,0] |
| 0 | 1 | j=1 | Start normal: bought[0] = max(-inf, res[0] - 1) = max(-inf, 0 - 1) = -1 | [0,0,0] | [-1,-1] | [0,0] |
| 1 | 7 | j=2 | Complete normal: res[2] = max(0, bought[1] + 7) = max(0, -1 + 7) = 6 | [0,0,6] | [-1,-1] | [0,0] |
| 1 | 7 | j=2 | Start normal: bought[1] = max(-1, res[1] - 7) = max(-1, 0 - 7) = -1 | [0,0,6] | [-1,-1] | [0,0] |
| 1 | 7 | j=1 | Complete normal: res[1] = max(0, bought[0] + 7) = max(0, -1 + 7) = 6 | [0,6,6] | [-1,-1] | [0,0] |
| 1 | 7 | j=1 | Start normal: bought[0] = max(-1, res[0] - 7) = max(-1, 0 - 7) = -1 | [0,6,6] | [-1,-1] | [0,0] |
| 2 | 9 | j=2 | Complete normal: res[2] = max(6, bought[1] + 9) = max(6, -1 + 9) = 8 | [0,6,8] | [-1,-1] | [0,0] |
| 2 | 9 | j=2 | Start normal: bought[1] = max(-1, res[1] - 9) = max(-1, 6 - 9) = -1 | [0,6,8] | [-1,-1] | [0,0] |
| 2 | 9 | j=1 | Complete normal: res[1] = max(6, bought[0] + 9) = max(6, -1 + 9) = 8 | [0,8,8] | [-1,-1] | [0,0] |
| 2 | 9 | j=1 | Start normal: bought[0] = max(-1, res[0] - 9) = max(-1, 0 - 9) = -1 | [0,8,8] | [-1,-1] | [0,0] |
| 3 | 8 | j=2 | Complete normal: res[2] = max(8, bought[1] + 8) = max(8, -1 + 8) = 8 | [0,8,8] | [-1,-1] | [0,0] |
| 3 | 8 | j=2 | Start short: sold[1] = max(0, res[1] + 8) = max(0, 8 + 8) = 16 | [0,8,8] | [-1,-1] | [0,16] |
| 3 | 8 | j=1 | Complete normal: res[1] = max(8, bought[0] + 8) = max(8, -1 + 8) = 8 | [0,8,8] | [-1,-1] | [0,16] |
| 3 | 8 | j=1 | Start short: sold[0] = max(0, res[0] + 8) = max(0, 0 + 8) = 8 | [0,8,8] | [-1,-1] | [8,16] |
| 4 | 2 | j=2 | Complete short: res[2] = max(8, sold[1] - 2) = max(8, 16 - 2) = 14 | [0,8,14] | [-1,-1] | [8,16] |
| 4 | 2 | j=1 | Complete short: res[1] = max(8, sold[0] - 2) = max(8, 8 - 2) = 8 | [0,8,14] | [-1,-1] | [8,16] |

**2.4 Increment and Loop:**

After processing all days, we check all values in the `res` array to find the maximum profit.

**2.5 Return Result:**

The maximum value in `res` is 14, which represents the maximum profit achievable with at most 2 transactions. This comes from: normal transaction (buy at 1, sell at 9) = 8, and short transaction (sell at 8, buy back at 2) = 6, total = 14.

Loading