Skip to content

Commit b422baf

Browse files
committed
feat: add Rotting Oranges
1 parent d73819b commit b422baf

File tree

19 files changed

+809
-1
lines changed

19 files changed

+809
-1
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"problem_name": "min_stack",
3+
"solution_class_name": "MinStack",
4+
"problem_number": "155",
5+
"problem_title": "Min Stack",
6+
"difficulty": "Medium",
7+
"topics": "Stack, Design",
8+
"tags": ["grind-75"],
9+
"readme_description": "Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.\n\nImplement the `MinStack` class:\n\n- `MinStack()` initializes the stack object.\n- `void push(int val)` pushes the element `val` onto the stack.\n- `void pop()` removes the element on the top of the stack.\n- `int top()` gets the top element of the stack.\n- `int getMin()` retrieves the minimum element in the stack.\n\nYou must implement a solution with `O(1)` time complexity for each function.",
10+
"readme_examples": [
11+
{
12+
"content": "```\nInput\n[\"MinStack\",\"push\",\"push\",\"push\",\"getMin\",\"pop\",\"top\",\"getMin\"]\n[[],[-2],[0],[-3],[],[],[],[]]\n\nOutput\n[null,null,null,null,-3,null,0,-2]\n```\n**Explanation:**\n```\nMinStack minStack = new MinStack();\nminStack.push(-2);\nminStack.push(0);\nminStack.push(-3);\nminStack.getMin(); // return -3\nminStack.pop();\nminStack.top(); // return 0\nminStack.getMin(); // return -2\n```"
13+
}
14+
],
15+
"readme_constraints": "- `-2^31 <= val <= 2^31 - 1`\n- Methods `pop`, `top` and `getMin` operations will always be called on **non-empty** stacks.\n- At most `3 * 10^4` calls will be made to `push`, `pop`, `top`, and `getMin`.",
16+
"readme_additional": "",
17+
"solution_imports": "",
18+
"solution_methods": [
19+
{ "name": "__init__", "parameters": "", "return_type": "None", "dummy_return": "" },
20+
{ "name": "push", "parameters": "val: int", "return_type": "None", "dummy_return": "" },
21+
{ "name": "pop", "parameters": "", "return_type": "None", "dummy_return": "" },
22+
{ "name": "top", "parameters": "", "return_type": "int", "dummy_return": "0" },
23+
{ "name": "get_min", "parameters": "", "return_type": "int", "dummy_return": "0" }
24+
],
25+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import MinStack",
26+
"test_class_name": "MinStack",
27+
"test_helper_methods": [],
28+
"test_methods": [
29+
{
30+
"name": "test_min_stack",
31+
"parametrize": "operations, inputs, expected",
32+
"parametrize_typed": "operations: list[str], inputs: list[list[int]], expected: list[int | None]",
33+
"test_cases": "[([\"MinStack\", \"push\", \"push\", \"push\", \"getMin\", \"pop\", \"top\", \"getMin\"], [[], [-2], [0], [-3], [], [], [], []], [None, None, None, None, -3, None, 0, -2]), ([\"MinStack\", \"push\", \"top\", \"getMin\", \"pop\"], [[], [5], [], [], []], [None, None, 5, 5, None]), ([\"MinStack\", \"push\", \"push\", \"push\", \"getMin\", \"pop\", \"getMin\", \"pop\", \"getMin\"], [[], [1], [1], [2], [], [], [], [], []], [None, None, None, None, 1, None, 1, None, 1]), ([\"MinStack\", \"push\", \"push\", \"getMin\", \"push\", \"getMin\", \"pop\", \"getMin\"], [[], [3], [1], [], [0], [], [], []], [None, None, None, 1, None, 0, None, 1])]",
34+
"body": "stack: MinStack | None = None\nresults: list[int | None] = []\nfor i, op in enumerate(operations):\n if op == \"MinStack\":\n stack = MinStack()\n results.append(None)\n elif op == \"push\" and stack is not None:\n stack.push(inputs[i][0])\n results.append(None)\n elif op == \"pop\" and stack is not None:\n stack.pop()\n results.append(None)\n elif op == \"top\" and stack is not None:\n results.append(stack.top())\n elif op == \"getMin\" and stack is not None:\n results.append(stack.get_min())\nassert results == expected"
35+
}
36+
],
37+
"playground_imports": "from solution import MinStack",
38+
"playground_test_case": "# Example test case\noperations = ['MinStack', 'push', 'push', 'push', 'getMin', 'pop', 'top', 'getMin']\ninputs = [[], [-2], [0], [-3], [], [], [], []]",
39+
"playground_execution": "stack = None\nresults: list[int | None] = []\nfor i, op in enumerate(operations):\n if op == 'MinStack':\n stack = MinStack()\n results.append(None)\n elif op == 'push' and stack is not None:\n stack.push(inputs[i][0])\n results.append(None)\n elif op == 'pop' and stack is not None:\n stack.pop()\n results.append(None)\n elif op == 'top' and stack is not None:\n results.append(stack.top())\n elif op == 'getMin' and stack is not None:\n results.append(stack.get_min())\nresults",
40+
"playground_assertion": "expected = [None, None, None, None, -3, None, 0, -2]\nassert results == expected"
41+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"problem_name": "number_of_islands",
3+
"solution_class_name": "Solution",
4+
"problem_number": "200",
5+
"problem_title": "Number of Islands",
6+
"difficulty": "Medium",
7+
"topics": "Array, Depth-First Search, Breadth-First Search, Union Find, Matrix",
8+
"tags": ["grind-75"],
9+
"readme_description": "Given an `m x n` 2D binary grid `grid` which represents a map of `'1'`s (land) and `'0'`s (water), return *the number of islands*.\n\nAn **island** is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.",
10+
"readme_examples": [
11+
{
12+
"content": "```\nInput: grid = [\n [\"1\",\"1\",\"1\",\"1\",\"0\"],\n [\"1\",\"1\",\"0\",\"1\",\"0\"],\n [\"1\",\"1\",\"0\",\"0\",\"0\"],\n [\"0\",\"0\",\"0\",\"0\",\"0\"]\n]\nOutput: 1\n```"
13+
},
14+
{
15+
"content": "```\nInput: grid = [\n [\"1\",\"1\",\"0\",\"0\",\"0\"],\n [\"1\",\"1\",\"0\",\"0\",\"0\"],\n [\"0\",\"0\",\"1\",\"0\",\"0\"],\n [\"0\",\"0\",\"0\",\"1\",\"1\"]\n]\nOutput: 3\n```"
16+
}
17+
],
18+
"readme_constraints": "- `m == grid.length`\n- `n == grid[i].length`\n- `1 <= m, n <= 300`\n- `grid[i][j]` is `'0'` or `'1'`.",
19+
"readme_additional": "",
20+
"solution_imports": "",
21+
"solution_methods": [
22+
{
23+
"name": "num_islands",
24+
"parameters": "grid: list[list[str]]",
25+
"return_type": "int",
26+
"dummy_return": "0"
27+
}
28+
],
29+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
30+
"test_class_name": "NumberOfIslands",
31+
"test_helper_methods": [
32+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
33+
],
34+
"test_methods": [
35+
{
36+
"name": "test_num_islands",
37+
"parametrize": "grid, expected",
38+
"parametrize_typed": "grid: list[list[str]], expected: int",
39+
"test_cases": "[([['1','1','1','1','0'],['1','1','0','1','0'],['1','1','0','0','0'],['0','0','0','0','0']], 1), ([['1','1','0','0','0'],['1','1','0','0','0'],['0','0','1','0','0'],['0','0','0','1','1']], 3), ([['1']], 1), ([['0']], 0), ([['1','0','1'],['0','1','0'],['1','0','1']], 5)]",
40+
"body": "result = self.solution.num_islands(grid)\nassert result == expected"
41+
}
42+
],
43+
"playground_imports": "from solution import Solution",
44+
"playground_test_case": "# Example test case\ngrid = [\n ['1','1','1','1','0'],\n ['1','1','0','1','0'],\n ['1','1','0','0','0'],\n ['0','0','0','0','0']\n]\nexpected = 1",
45+
"playground_execution": "result = Solution().num_islands(grid)\nresult",
46+
"playground_assertion": "assert result == expected"
47+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"problem_name": "rotting_oranges",
3+
"solution_class_name": "Solution",
4+
"problem_number": "994",
5+
"problem_title": "Rotting Oranges",
6+
"difficulty": "Medium",
7+
"topics": "Array, Breadth-First Search, Matrix",
8+
"tags": ["grind-75"],
9+
"readme_description": "You are given an `m x n` `grid` where each cell can have one of three values:\n\n- `0` representing an empty cell,\n- `1` representing a fresh orange, or\n- `2` representing a rotten orange.\n\nEvery minute, any fresh orange that is **4-directionally adjacent** to a rotten orange becomes rotten.\n\nReturn *the minimum number of minutes that must elapse until no cell has a fresh orange*. If *this is impossible, return* `-1`.",
10+
"readme_examples": [
11+
{
12+
"content": "![Example 1](https://assets.leetcode.com/uploads/2019/02/16/oranges.png)\n\n```\nInput: grid = [[2,1,1],[1,1,0],[0,1,1]]\nOutput: 4\n```"
13+
},
14+
{
15+
"content": "```\nInput: grid = [[2,1,1],[0,1,1],[1,0,1]]\nOutput: -1\n```\n**Explanation:** The orange in the bottom left corner (row 2, column 0) is never rotten, because rotting only happens 4-directionally."
16+
},
17+
{
18+
"content": "```\nInput: grid = [[0,2]]\nOutput: 0\n```\n**Explanation:** Since there are already no fresh oranges at minute 0, the answer is just 0."
19+
}
20+
],
21+
"readme_constraints": "- `m == grid.length`\n- `n == grid[i].length`\n- `1 <= m, n <= 10`\n- `grid[i][j]` is `0`, `1`, or `2`.",
22+
"readme_additional": "",
23+
"solution_imports": "",
24+
"solution_methods": [
25+
{
26+
"name": "oranges_rotting",
27+
"parameters": "grid: list[list[int]]",
28+
"return_type": "int",
29+
"dummy_return": "0"
30+
}
31+
],
32+
"test_imports": "import pytest\nfrom leetcode_py.test_utils import logged_test\nfrom .solution import Solution",
33+
"test_class_name": "TestRottingOranges",
34+
"test_helper_methods": [
35+
{ "name": "setup_method", "parameters": "", "body": "self.solution = Solution()" }
36+
],
37+
"test_methods": [
38+
{
39+
"name": "test_oranges_rotting",
40+
"parametrize": "grid, expected",
41+
"parametrize_typed": "grid: list[list[int]], expected: int",
42+
"test_cases": "[([[2, 1, 1], [1, 1, 0], [0, 1, 1]], 4), ([[2, 1, 1], [0, 1, 1], [1, 0, 1]], -1), ([[0, 2]], 0), ([[0]], 0), ([[1]], -1), ([[2]], 0), ([[1, 2]], 1), ([[2, 1]], 1), ([[0, 1, 2]], 1), ([[2, 2], [1, 1], [0, 0]], 1), ([[2, 1, 1], [1, 1, 1], [0, 1, 2]], 2)]",
43+
"body": "result = self.solution.oranges_rotting(grid)\nassert result == expected"
44+
}
45+
],
46+
"playground_imports": "from solution import Solution",
47+
"playground_test_case": "# Example test case\ngrid = [[2, 1, 1], [1, 1, 0], [0, 1, 1]]\nexpected = 4",
48+
"playground_execution": "result = Solution().oranges_rotting(grid)\nresult",
49+
"playground_assertion": "assert result == expected"
50+
}

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
PYTHON_VERSION = 3.13
2-
PROBLEM ?= course_schedule
2+
PROBLEM ?= rotting_oranges
33
FORCE ?= 0
44
COMMA := ,
55

leetcode/min_stack/README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Min Stack
2+
3+
**Difficulty:** Medium
4+
**Topics:** Stack, Design
5+
**Tags:** grind-75
6+
7+
**LeetCode:** [Problem 155](https://leetcode.com/problems/min-stack/description/)
8+
9+
## Problem Description
10+
11+
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
12+
13+
Implement the `MinStack` class:
14+
15+
- `MinStack()` initializes the stack object.
16+
- `void push(int val)` pushes the element `val` onto the stack.
17+
- `void pop()` removes the element on the top of the stack.
18+
- `int top()` gets the top element of the stack.
19+
- `int getMin()` retrieves the minimum element in the stack.
20+
21+
You must implement a solution with `O(1)` time complexity for each function.
22+
23+
## Examples
24+
25+
### Example 1:
26+
27+
```
28+
Input
29+
["MinStack","push","push","push","getMin","pop","top","getMin"]
30+
[[],[-2],[0],[-3],[],[],[],[]]
31+
32+
Output
33+
[null,null,null,null,-3,null,0,-2]
34+
```
35+
36+
**Explanation:**
37+
38+
```
39+
MinStack minStack = new MinStack();
40+
minStack.push(-2);
41+
minStack.push(0);
42+
minStack.push(-3);
43+
minStack.getMin(); // return -3
44+
minStack.pop();
45+
minStack.top(); // return 0
46+
minStack.getMin(); // return -2
47+
```
48+
49+
## Constraints
50+
51+
- `-2^31 <= val <= 2^31 - 1`
52+
- Methods `pop`, `top` and `getMin` operations will always be called on **non-empty** stacks.
53+
- At most `3 * 10^4` calls will be made to `push`, `pop`, `top`, and `getMin`.

leetcode/min_stack/__init__.py

Whitespace-only changes.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 1,
6+
"id": "imports",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": [
10+
"from solution import MinStack"
11+
]
12+
},
13+
{
14+
"cell_type": "code",
15+
"execution_count": 2,
16+
"id": "setup",
17+
"metadata": {},
18+
"outputs": [],
19+
"source": [
20+
"# Example test case\n",
21+
"operations = [\"MinStack\", \"push\", \"push\", \"push\", \"getMin\", \"pop\", \"top\", \"getMin\"]\n",
22+
"inputs = [[], [-2], [0], [-3], [], [], [], []]"
23+
]
24+
},
25+
{
26+
"cell_type": "code",
27+
"execution_count": 3,
28+
"id": "execute",
29+
"metadata": {},
30+
"outputs": [
31+
{
32+
"data": {
33+
"text/plain": [
34+
"[None, None, None, None, -3, None, 0, -2]"
35+
]
36+
},
37+
"execution_count": 3,
38+
"metadata": {},
39+
"output_type": "execute_result"
40+
}
41+
],
42+
"source": [
43+
"stack = None\n",
44+
"results: list[int | None] = []\n",
45+
"for i, op in enumerate(operations):\n",
46+
" if op == \"MinStack\":\n",
47+
" stack = MinStack()\n",
48+
" results.append(None)\n",
49+
" elif op == \"push\" and stack is not None:\n",
50+
" stack.push(inputs[i][0])\n",
51+
" results.append(None)\n",
52+
" elif op == \"pop\" and stack is not None:\n",
53+
" stack.pop()\n",
54+
" results.append(None)\n",
55+
" elif op == \"top\" and stack is not None:\n",
56+
" results.append(stack.top())\n",
57+
" elif op == \"getMin\" and stack is not None:\n",
58+
" results.append(stack.get_min())\n",
59+
"results"
60+
]
61+
},
62+
{
63+
"cell_type": "code",
64+
"execution_count": 4,
65+
"id": "test",
66+
"metadata": {},
67+
"outputs": [],
68+
"source": [
69+
"expected = [None, None, None, None, -3, None, 0, -2]\n",
70+
"assert results == expected"
71+
]
72+
}
73+
],
74+
"metadata": {
75+
"kernelspec": {
76+
"display_name": "leetcode-py-py3.13",
77+
"language": "python",
78+
"name": "python3"
79+
},
80+
"language_info": {
81+
"codemirror_mode": {
82+
"name": "ipython",
83+
"version": 3
84+
},
85+
"file_extension": ".py",
86+
"mimetype": "text/x-python",
87+
"name": "python",
88+
"nbconvert_exporter": "python",
89+
"pygments_lexer": "ipython3",
90+
"version": "3.13.7"
91+
}
92+
},
93+
"nbformat": 4,
94+
"nbformat_minor": 5
95+
}

leetcode/min_stack/solution.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
class MinStack:
2+
# Time: O(1) for all operations
3+
# Space: O(n) where n is number of elements
4+
def __init__(self) -> None:
5+
self.stack: list[int] = []
6+
self.min_stack: list[int] = []
7+
8+
# Time: O(1)
9+
# Space: O(1)
10+
def push(self, val: int) -> None:
11+
self.stack.append(val)
12+
if not self.min_stack or val <= self.min_stack[-1]:
13+
self.min_stack.append(val)
14+
15+
# Time: O(1)
16+
# Space: O(1)
17+
def pop(self) -> None:
18+
if self.stack[-1] == self.min_stack[-1]:
19+
self.min_stack.pop()
20+
self.stack.pop()
21+
22+
# Time: O(1)
23+
# Space: O(1)
24+
def top(self) -> int:
25+
return self.stack[-1]
26+
27+
# Time: O(1)
28+
# Space: O(1)
29+
def get_min(self) -> int:
30+
return self.min_stack[-1]
31+
32+
33+
# Example walkthrough: push(-2), push(0), push(-3), getMin(), pop(), top(), getMin()
34+
#
35+
# Initial: stack=[], min_stack=[]
36+
#
37+
# push(-2): stack=[-2], min_stack=[-2] (first element, add to both)
38+
# push(0): stack=[-2,0], min_stack=[-2] (0 > -2, don't add to min_stack)
39+
# push(-3): stack=[-2,0,-3], min_stack=[-2,-3] (-3 <= -2, add to min_stack)
40+
# getMin(): return -3 (top of min_stack)
41+
# pop(): stack=[-2,0], min_stack=[-2] (-3 was min, remove from both stacks)
42+
# top(): return 0 (top of main stack)
43+
# getMin(): return -2 (top of min_stack after pop)

leetcode/min_stack/tests.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import pytest
2+
3+
from leetcode_py.test_utils import logged_test
4+
5+
from .solution import MinStack
6+
7+
8+
class TestMinStack:
9+
@pytest.mark.parametrize(
10+
"operations, inputs, expected",
11+
[
12+
(
13+
["MinStack", "push", "push", "push", "getMin", "pop", "top", "getMin"],
14+
[[], [-2], [0], [-3], [], [], [], []],
15+
[None, None, None, None, -3, None, 0, -2],
16+
),
17+
(
18+
["MinStack", "push", "top", "getMin", "pop"],
19+
[[], [5], [], [], []],
20+
[None, None, 5, 5, None],
21+
),
22+
(
23+
["MinStack", "push", "push", "push", "getMin", "pop", "getMin", "pop", "getMin"],
24+
[[], [1], [1], [2], [], [], [], [], []],
25+
[None, None, None, None, 1, None, 1, None, 1],
26+
),
27+
(
28+
["MinStack", "push", "push", "getMin", "push", "getMin", "pop", "getMin"],
29+
[[], [3], [1], [], [0], [], [], []],
30+
[None, None, None, 1, None, 0, None, 1],
31+
),
32+
],
33+
)
34+
@logged_test
35+
def test_min_stack(self, operations: list[str], inputs: list[list[int]], expected: list[int | None]):
36+
stack: MinStack | None = None
37+
results: list[int | None] = []
38+
for i, op in enumerate(operations):
39+
if op == "MinStack":
40+
stack = MinStack()
41+
results.append(None)
42+
elif op == "push" and stack is not None:
43+
stack.push(inputs[i][0])
44+
results.append(None)
45+
elif op == "pop" and stack is not None:
46+
stack.pop()
47+
results.append(None)
48+
elif op == "top" and stack is not None:
49+
results.append(stack.top())
50+
elif op == "getMin" and stack is not None:
51+
results.append(stack.get_min())
52+
assert results == expected

0 commit comments

Comments
 (0)