Skip to content

Commit 23deabe

Browse files
renovate[bot]wislerttclaude
authored
feat: add 10 more leetcode problems (#161)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Wisaroot Lertthaweedech <l.wisaroot@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 0d9354d commit 23deabe

77 files changed

Lines changed: 2985 additions & 333 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/.dev/check_problem_lists.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@
22

33
import sys
44
from pathlib import Path
5+
from typing import TypedDict
56

67
# Import the problem lists
78
sys.path.append(str(Path(__file__).parent.parent.parent))
89
from problem_lists import available_lists
910
from problem_lists.utils import get_existing_problems
1011

1112

13+
class CheckResult(TypedDict):
14+
have: set[int]
15+
missing: set[int]
16+
total: int
17+
18+
1219
def check_problem_list(tag_name, problem_tuples, existing_problems):
1320
"""Check how many problems from a list are available."""
1421
problem_numbers = {num for num, _ in problem_tuples}
@@ -34,7 +41,7 @@ def check_problem_lists(tag_names=None):
3441
existing = get_existing_problems()
3542
print(f"Total existing problems in JSON: {len(existing)}")
3643

37-
results = {}
44+
results: dict[str, CheckResult] = {}
3845

3946
# Check each specified list
4047
for tag_name, problem_tuples in available_lists.items():

.github/workflows/security.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,6 @@ jobs:
3030
with:
3131
fetch-depth: 0
3232

33-
- uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7 # v2.3.9
33+
- uses: gitleaks/gitleaks-action@e0c47f4f8be36e29cdc102c57e68cb5cbf0e8d1e # v3.0.0
3434
env:
3535
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,14 @@ jobs:
9393

9494
- name: upload-coverage-reports-to-codecov
9595
if: matrix.python-version == inputs.target_python_version && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository)
96-
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
96+
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
9797
with:
9898
fail_ci_if_error: true
9999
token: ${{ secrets.CODECOV_TOKEN }}
100100
verbose: true
101101

102102
- name: sonarqube-scan
103103
if: matrix.python-version == inputs.target_python_version && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository)
104-
uses: SonarSource/sonarqube-scan-action@59db25f34e16620e48ab4bb9e4a5dce155cb5432 # v8.0.0
104+
uses: SonarSource/sonarqube-scan-action@713881670b6b3676cda39549040e2d88c70d582e # v8.2.0
105105
env:
106106
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,3 +573,5 @@ $RECYCLE.BIN/
573573
*.lnk
574574

575575
# End of https://www.toptal.com/developers/gitignore/api/macos,windows,visualstudiocode,intellij+all,node,java,python,go,ssh,terragrunt,terraform
576+
577+
.playwright-mcp

bakefile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
class MyBakebook(GitHubActionsTools, PythonLibSpace):
2020
ci: bool = False
21-
problem: str = "powx_n"
21+
problem: str = "copy_list_with_random_pointer"
2222

2323
def lint(self) -> None:
2424
self.ctx.run("uv run python scripts/sort_tags.py")
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Copy List with Random Pointer
2+
3+
**Difficulty:** Medium
4+
**Topics:** Hash Table, Linked List
5+
**Tags:** neetcode-150
6+
7+
**LeetCode:** [Problem 138](https://leetcode.com/problems/copy-list-with-random-pointer/description/)
8+
9+
## Problem Description
10+
11+
A linked list of length `n` is given such that each node contains an additional **random pointer**, which could point to any node in the list, or `null`.
12+
13+
Construct a [**deep copy**](https://en.wikipedia.org/wiki/Object_copying#Deep_copy) of the list. The deep copy should consist of exactly `n` **brand new** nodes, where each new node has its value set to the value of its corresponding original node. Both the `next` and `random` pointer of the new nodes should point to new nodes in the copied list such that the pointers in the original list and copied list represent the same list state. **None of the pointers in the new list should point to nodes in the original list**.
14+
15+
Return _the head of the copied linked list_.
16+
17+
The linked list is represented in the input/output as a list of `n` nodes. Each node is represented as a pair of `[val, random_index]` where:
18+
19+
- `val`: an integer representing `Node.val`
20+
- `random_index`: the index of the node (range from `0` to `n-1`) that the `random` pointer points to, or `null` if it does not point to any node.
21+
22+
## Examples
23+
24+
### Example 1:
25+
26+
![Example 1](https://assets.leetcode.com/uploads/2019/12/18/e1.png)
27+
28+
```
29+
Input: head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
30+
Output: [[7,null],[13,0],[11,4],[10,2],[1,0]]
31+
```
32+
33+
### Example 2:
34+
35+
![Example 2](https://assets.leetcode.com/uploads/2019/12/18/e2.png)
36+
37+
```
38+
Input: head = [[1,1],[2,1]]
39+
Output: [[1,1],[2,1]]
40+
```
41+
42+
### Example 3:
43+
44+
![Example 3](https://assets.leetcode.com/uploads/2019/12/18/e3.png)
45+
46+
```
47+
Input: head = [[3,null],[3,0],[3,null]]
48+
Output: [[3,null],[3,0],[3,null]]
49+
```
50+
51+
## Constraints
52+
53+
- 0 <= n <= 1000
54+
- -10^4 <= Node.val <= 10^4
55+
- Node.random is null or points to some node in the linked list.

leetcode/copy_list_with_random_pointer/__init__.py

Whitespace-only changes.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from .solution import Node
2+
3+
4+
def _build_random_list(nodes: list[list[int | None]]) -> Node | None:
5+
if not nodes:
6+
return None
7+
created: list[Node] = []
8+
for node_spec in nodes:
9+
val = node_spec[0]
10+
assert isinstance(val, int)
11+
created.append(Node(val))
12+
for i, node_spec in enumerate(nodes):
13+
if i + 1 < len(created):
14+
created[i].next = created[i + 1]
15+
rand_idx = node_spec[1]
16+
if rand_idx is not None:
17+
created[i].random = created[rand_idx]
18+
return created[0]
19+
20+
21+
def _serialize_random_list(head: Node | None) -> list[list[int | None]]:
22+
index_by_id: dict[int, int] = {}
23+
cur: Node | None = head
24+
i = 0
25+
while cur is not None:
26+
index_by_id[id(cur)] = i
27+
i += 1
28+
cur = cur.next
29+
result: list[list[int | None]] = []
30+
cur = head
31+
while cur is not None:
32+
rand_idx = index_by_id[id(cur.random)] if cur.random is not None else None
33+
result.append([cur.val, rand_idx])
34+
cur = cur.next
35+
return result
36+
37+
38+
def run_copy_random_list(solution_class: type, nodes: list[list[int | None]]):
39+
implementation = solution_class()
40+
head = _build_random_list(nodes)
41+
copied = implementation.copy_random_list(head)
42+
return _serialize_random_list(copied)
43+
44+
45+
def assert_copy_random_list(
46+
result: list[list[int | None]], expected: list[list[int | None]]
47+
) -> bool:
48+
assert result == expected
49+
return True
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# ---
2+
# jupyter:
3+
# jupytext:
4+
# text_representation:
5+
# extension: .py
6+
# format_name: percent
7+
# format_version: '1.3'
8+
# jupytext_version: 1.19.3
9+
# kernelspec:
10+
# display_name: leetcode-py-py3.13
11+
# language: python
12+
# name: python3
13+
# ---
14+
15+
# %%
16+
from helpers import assert_copy_random_list, run_copy_random_list
17+
from solution import Solution
18+
19+
# %%
20+
# Example test case (each node is [val, random_index])
21+
nodes = [[7, None], [13, 0], [11, 4], [10, 2], [1, 0]]
22+
expected = [[7, None], [13, 0], [11, 4], [10, 2], [1, 0]]
23+
24+
# %%
25+
result = run_copy_random_list(Solution, nodes)
26+
result
27+
28+
# %%
29+
assert_copy_random_list(result, expected)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from __future__ import annotations
2+
3+
4+
class Node:
5+
def __init__(self, x: int, next: Node | None = None, random: Node | None = None):
6+
self.val = int(x)
7+
self.next = next
8+
self.random = random
9+
10+
11+
class Solution:
12+
# Time: O(n)
13+
# Space: O(1) extra (interweaves clones into the original list)
14+
def copy_random_list(self, head: Node | None) -> Node | None:
15+
if head is None:
16+
return None
17+
18+
# Phase 1: insert each clone right after its original node
19+
current: Node | None = head
20+
while current is not None:
21+
nxt = current.next
22+
clone = Node(current.val, nxt)
23+
current.next = clone
24+
current = nxt
25+
26+
# Phase 2: wire each clone's random from its original's random
27+
current = head
28+
while current is not None:
29+
clone = current.next
30+
assert clone is not None
31+
if current.random is not None:
32+
rand_clone = current.random.next
33+
assert rand_clone is not None
34+
clone.random = rand_clone
35+
current = clone.next
36+
37+
# Phase 3: detach clones, restore the original, return the copy head
38+
current = head
39+
copy_head = head.next
40+
while current is not None:
41+
clone = current.next
42+
assert clone is not None
43+
current.next = clone.next
44+
tail = clone.next
45+
clone.next = tail.next if tail is not None else None
46+
current = current.next
47+
48+
return copy_head

0 commit comments

Comments
 (0)