Compare commits

...
Author SHA1 Message Date
Prad Nukala 2d37d6bc4d feat(work): add Python solutions for Is Subsequence and Container With Most Water 2026-08-24 16:22:00 -04:00
Prad Nukala 8661e10832 docs(docs): add solution documentation for Container With Most Water and Is Subsequence 2026-08-24 16:21:57 -04:00
Prad Nukala af03ecb9a4 feat(work): add Python solutions for Two Sum, 3Sum, Two Sum II and remove unused JavaScript stubs 2026-08-24 15:32:33 -04:00
Prad Nukala fe7556bf1e docs(docs): add Python solutions and new Two Sum documentation 2026-08-24 15:32:30 -04:00
Prad Nukala 382475b7f1 feat(ci): auto-close problem issues when a solution lands in work/
Reconciles work/ against open `problem` issues instead of diffing the push,
so re-runs are no-ops and backfills need no special casing.

Skips scaffolded stubs: `bun run pick` writes a statement header plus an
empty body, so file existence alone must not close an issue.
2026-08-24 14:31:36 -04:00
Prad Nukala 7743ca18bd docs(readme): add campaign index linking phase milestones and topic issues 2026-08-24 14:31:36 -04:00
18 changed files with 938 additions and 300 deletions

No files matched your search

+34
View File
@@ -0,0 +1,34 @@
name: Close Solved
on:
push:
branches: [main]
paths: ["work/**"]
workflow_dispatch:
inputs:
dry_run:
description: Report matches without closing anything
type: boolean
default: false
permissions:
contents: read
issues: write
concurrency:
group: close-solved
cancel-in-progress: false
jobs:
close:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
# No install step: the script only uses Bun builtins + fetch.
- run: bun scripts/close-solved.ts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DRY_RUN: ${{ inputs.dry_run }}
+96
View File
@@ -8,6 +8,102 @@
</p>
## Campaign
<sub>8-week interview-prep fight camp. Each phase is a milestone; each topic an issue; each problem a sub-issue. Core count reflects closed sub-issues.</sub>
<table>
<thead>
<tr>
<th align="center">Phase</th>
<th align="center">Wk</th>
<th align="left">Date</th>
<th align="left">Topic</th>
<th align="center">Core</th>
<th align="left">Core&nbsp;problems</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="7" align="center"><strong>I</strong><br><sub>Linear Structures</sub></td>
<td align="center">1</td><td>Mon Aug 17</td><td><a href="https://github.com/prdlk/leetcode/issues/3"><strong>01</strong> · Hash-Based Lookup</a></td><td align="center">5/5</td><td><a href="https://leetcode.com/problems/contains-duplicate/">217</a> · <a href="https://leetcode.com/problems/valid-anagram/">242</a> · <a href="https://leetcode.com/problems/two-sum/">1</a> · <a href="https://leetcode.com/problems/group-anagrams/">49</a> · <a href="https://leetcode.com/problems/top-k-frequent-elements/">347</a></td>
</tr>
<tr>
<td align="center">1</td><td>Tue Aug 18</td><td><a href="https://github.com/prdlk/leetcode/issues/4"><strong>02</strong> · Prefix Sum</a></td><td align="center">3/3</td><td><a href="https://leetcode.com/problems/range-sum-query-immutable/">303</a> · <a href="https://leetcode.com/problems/product-of-array-except-self/">238</a> · <a href="https://leetcode.com/problems/subarray-sum-equals-k/">560</a></td>
</tr>
<tr>
<td align="center">2</td><td>Mon Aug 24</td><td><a href="https://github.com/prdlk/leetcode/issues/5"><strong>03</strong> · Two Pointers</a></td><td align="center">2/4</td><td><a href="https://leetcode.com/problems/valid-palindrome/">125</a> · <a href="https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/">167</a> · <a href="https://leetcode.com/problems/3sum/">15</a> · <a href="https://leetcode.com/problems/container-with-most-water/">11</a></td>
</tr>
<tr>
<td align="center">2</td><td>Tue Aug 25</td><td><a href="https://github.com/prdlk/leetcode/issues/6"><strong>04</strong> · Sliding Window</a></td><td align="center">1/4</td><td><a href="https://leetcode.com/problems/best-time-to-buy-and-sell-stock/">121</a> · <a href="https://leetcode.com/problems/longest-substring-without-repeating-characters/">3</a> · <a href="https://leetcode.com/problems/longest-repeating-character-replacement/">424</a> · <a href="https://leetcode.com/problems/permutation-in-string/">567</a></td>
</tr>
<tr>
<td align="center">2</td><td>Wed Aug 26</td><td><a href="https://github.com/prdlk/leetcode/issues/7"><strong>05</strong> · Binary Search</a></td><td align="center">3/5</td><td><a href="https://leetcode.com/problems/binary-search/">704</a> · <a href="https://leetcode.com/problems/koko-eating-bananas/">875</a> · <a href="https://leetcode.com/problems/search-in-rotated-sorted-array/">33</a> · <a href="https://leetcode.com/problems/search-a-2d-matrix/">74</a> · <a href="https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/">153</a></td>
</tr>
<tr>
<td align="center">2</td><td>Thu Aug 27</td><td><a href="https://github.com/prdlk/leetcode/issues/8"><strong>06</strong> · Stack</a></td><td align="center">0/3</td><td><a href="https://leetcode.com/problems/valid-parentheses/">20</a> · <a href="https://leetcode.com/problems/min-stack/">155</a> · <a href="https://leetcode.com/problems/evaluate-reverse-polish-notation/">150</a></td>
</tr>
<tr>
<td align="center">2</td><td>Fri Aug 28</td><td><a href="https://github.com/prdlk/leetcode/issues/9"><strong>07</strong> · Monotonic Stack</a></td><td align="center">0/2</td><td><a href="https://leetcode.com/problems/daily-temperatures/">739</a> · <a href="https://leetcode.com/problems/car-fleet/">853</a></td>
</tr>
<tr>
<td rowspan="3" align="center"><strong>II</strong><br><sub>Nodal & Grid</sub></td>
<td align="center">3</td><td>Mon Aug 31</td><td><a href="https://github.com/prdlk/leetcode/issues/10"><strong>08</strong> · Linked List</a></td><td align="center">0/3</td><td><a href="https://leetcode.com/problems/reverse-linked-list/">206</a> · <a href="https://leetcode.com/problems/merge-two-sorted-lists/">21</a> · <a href="https://leetcode.com/problems/linked-list-cycle/">141</a></td>
</tr>
<tr>
<td align="center">3</td><td>Tue Sep 1</td><td><a href="https://github.com/prdlk/leetcode/issues/11"><strong>09</strong> · Hybrid Structures</a></td><td align="center">0/2</td><td><a href="https://leetcode.com/problems/lru-cache/">146</a> · <a href="https://leetcode.com/problems/add-two-numbers/">2</a></td>
</tr>
<tr>
<td align="center">3</td><td>Wed Sep 2</td><td><a href="https://github.com/prdlk/leetcode/issues/12"><strong>10</strong> · Matrix Index Math</a></td><td align="center">0/3</td><td><a href="https://leetcode.com/problems/rotate-image/">48</a> · <a href="https://leetcode.com/problems/spiral-matrix/">54</a> · <a href="https://leetcode.com/problems/set-matrix-zeroes/">73</a></td>
</tr>
<tr>
<td rowspan="5" align="center"><strong>III</strong><br><sub>Hierarchical</sub></td>
<td align="center">3</td><td>Thu Sep 3</td><td><a href="https://github.com/prdlk/leetcode/issues/13"><strong>11</strong> · Tree DFS</a></td><td align="center">0/3</td><td><a href="https://leetcode.com/problems/invert-binary-tree/">226</a> · <a href="https://leetcode.com/problems/maximum-depth-of-binary-tree/">104</a> · <a href="https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/">236</a></td>
</tr>
<tr>
<td align="center">3</td><td>Fri Sep 4</td><td><a href="https://github.com/prdlk/leetcode/issues/14"><strong>12</strong> · Tree BFS</a></td><td align="center">0/3</td><td><a href="https://leetcode.com/problems/binary-tree-level-order-traversal/">102</a> · <a href="https://leetcode.com/problems/binary-tree-right-side-view/">199</a> · <a href="https://leetcode.com/problems/count-good-nodes-in-binary-tree/">1448</a></td>
</tr>
<tr>
<td align="center">4</td><td>Mon Sep 7</td><td><a href="https://github.com/prdlk/leetcode/issues/15"><strong>13</strong> · Binary Search Tree</a></td><td align="center">0/3</td><td><a href="https://leetcode.com/problems/validate-binary-search-tree/">98</a> · <a href="https://leetcode.com/problems/kth-smallest-element-in-a-bst/">230</a> · <a href="https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/">235</a></td>
</tr>
<tr>
<td align="center">4</td><td>Tue Sep 8</td><td><a href="https://github.com/prdlk/leetcode/issues/16"><strong>14</strong> · Heap / Priority Queue</a></td><td align="center">0/3</td><td><a href="https://leetcode.com/problems/kth-largest-element-in-an-array/">215</a> · <a href="https://leetcode.com/problems/k-closest-points-to-origin/">973</a> · <a href="https://leetcode.com/problems/merge-k-sorted-lists/">23</a></td>
</tr>
<tr>
<td align="center">4</td><td>Wed Sep 9</td><td><a href="https://github.com/prdlk/leetcode/issues/17"><strong>15</strong> · Trie</a></td><td align="center">0/2</td><td><a href="https://leetcode.com/problems/implement-trie-prefix-tree/">208</a> · <a href="https://leetcode.com/problems/design-add-and-search-words-data-structure/">211</a></td>
</tr>
<tr>
<td rowspan="4" align="center"><strong>IV</strong><br><sub>Relational</sub></td>
<td align="center">4</td><td>Thu Sep 10</td><td><a href="https://github.com/prdlk/leetcode/issues/18"><strong>16</strong> · Graph DFS</a></td><td align="center">0/3</td><td><a href="https://leetcode.com/problems/number-of-islands/">200</a> · <a href="https://leetcode.com/problems/clone-graph/">133</a> · <a href="https://leetcode.com/problems/pacific-atlantic-water-flow/">417</a></td>
</tr>
<tr>
<td align="center">4</td><td>Fri Sep 11</td><td><a href="https://github.com/prdlk/leetcode/issues/19"><strong>17</strong> · Graph BFS</a></td><td align="center">0/2</td><td><a href="https://leetcode.com/problems/rotting-oranges/">994</a> · <a href="https://leetcode.com/problems/word-ladder/">127</a></td>
</tr>
<tr>
<td align="center">5</td><td>Mon Sep 14</td><td><a href="https://github.com/prdlk/leetcode/issues/20"><strong>18</strong> · Topological Sort</a></td><td align="center">0/2</td><td><a href="https://leetcode.com/problems/course-schedule/">207</a> · <a href="https://leetcode.com/problems/course-schedule-ii/">210</a></td>
</tr>
<tr>
<td align="center">5</td><td>Tue Sep 15</td><td><a href="https://github.com/prdlk/leetcode/issues/21"><strong>19</strong> · Union-Find</a></td><td align="center">0/2</td><td><a href="https://leetcode.com/problems/redundant-connection/">684</a> · <a href="https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/">323</a></td>
</tr>
<tr>
<td rowspan="5" align="center"><strong>V</strong><br><sub>Decision Space</sub></td>
<td align="center">5</td><td>Wed Sep 16</td><td><a href="https://github.com/prdlk/leetcode/issues/22"><strong>20</strong> · Backtracking</a></td><td align="center">0/3</td><td><a href="https://leetcode.com/problems/subsets/">78</a> · <a href="https://leetcode.com/problems/combination-sum/">39</a> · <a href="https://leetcode.com/problems/permutations/">46</a></td>
</tr>
<tr>
<td align="center">5</td><td>Thu Sep 17</td><td><a href="https://github.com/prdlk/leetcode/issues/23"><strong>21</strong> · 1-D Dynamic Programming</a></td><td align="center">0/3</td><td><a href="https://leetcode.com/problems/climbing-stairs/">70</a> · <a href="https://leetcode.com/problems/house-robber/">198</a> · <a href="https://leetcode.com/problems/coin-change/">322</a></td>
</tr>
<tr>
<td align="center">5</td><td>Fri Sep 18</td><td><a href="https://github.com/prdlk/leetcode/issues/24"><strong>22</strong> · Multi-D / Grid DP</a></td><td align="center">0/3</td><td><a href="https://leetcode.com/problems/unique-paths/">62</a> · <a href="https://leetcode.com/problems/minimum-path-sum/">64</a> · <a href="https://leetcode.com/problems/longest-common-subsequence/">1143</a></td>
</tr>
<tr>
<td align="center">6</td><td>Mon Sep 21</td><td><a href="https://github.com/prdlk/leetcode/issues/25"><strong>23</strong> · Greedy</a></td><td align="center">0/3</td><td><a href="https://leetcode.com/problems/maximum-subarray/">53</a> · <a href="https://leetcode.com/problems/jump-game/">55</a> · <a href="https://leetcode.com/problems/gas-station/">134</a></td>
</tr>
<tr>
<td align="center">6</td><td>Tue Sep 22</td><td><a href="https://github.com/prdlk/leetcode/issues/26"><strong>24</strong> · Intervals</a></td><td align="center">0/3</td><td><a href="https://leetcode.com/problems/insert-interval/">57</a> · <a href="https://leetcode.com/problems/merge-intervals/">56</a> · <a href="https://leetcode.com/problems/non-overlapping-intervals/">435</a></td>
</tr>
</tbody>
</table>
## Phase I — Linear Structures (Week 1)
<table>
+47
View File
@@ -0,0 +1,47 @@
---
title: '1. Two Sum'
description: You are given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target
sidebar:
label: 'Two Sum'
badge: 'Easy'
---
<Badge variant="accent">Hash Table</Badge>
::::warning
Can you come up with an algorithm that is less than O(n^2) time complexity?
::::
### Example 1:
- Input: `nums = [2,7,11,15], target = 9`
- Output: `[0,1]`
- Explanation: Because `nums[0] + nums[1]` == `9`, we return [0, 1].
### Example 2:
- Input: `nums = [3,2,4], target = 6`
- Output: `[1,2]`
### Example 3:
- Input: `nums = [3,3], target = 6`
- Output: `[0,1]`
### Constraints:
- `2 <= nums.length <= 10^4`
- `-10^9 <= nums[i] <= 10^9`
- `-10^9 <= target <= 10^9`
- Only one valid answer exists.
## Solution
```py
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
seen = {}
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i
return []
```
@@ -0,0 +1,48 @@
---
title: '11. Container With Most Water'
description: You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the i^th line are (i, 0) and (i, height[i])
sidebar:
label: 'Container With Most Water'
badge: 'Medium'
---
<Badge variant="accent">Two Pointers</Badge>
::::warning
Notice that you may not slant the container.
::::
### Example 1:
- Input: `height = [1,8,6,2,5,4,8,3,7]`
- Output: `49`
- Explanation: The above vertical lines are represented by array `[1,8,6,2,5,4,8,3,7]`. In this case, the max area of water (blue section) the container can contain is `49`.
### Example 2:
- Input: `height = [1,1]`
- Output: `1`
### Constraints:
- `n == height.length`
- `2 <= n <= 10^5`
- `0 <= height[i] <= 10^4`
## Solution
```py
class Solution:
def maxArea(self, height: List[int]) -> int: # noqa: F821
res = 0
left = 0
right = len(height) - 1
while left < right:
area = (right - left) * min(height[left], height[right])
res = max(res, area)
if height[left] < height[right]:
left += 1
else:
right -= 1
return res
```
+40 -7
View File
@@ -34,12 +34,45 @@ Notice that the solution set must not contain duplicate triplets.
## Solution
```js
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
```py
class Solution:
def threeSum(self, nums: list[int]) -> list[list[int]]:
nums.sort()
result = []
n = len(nums)
};
for i in range(n):
# skip all zero
if i > 0 and nums[i] == nums[i - 1]:
continue
# two pointers
left = i + 1
right = n - 1
target = -nums[i]
while left < right:
current = nums[left] + nums[right]
if current == target:
result.append([nums[i], nums[left], nums[right]])
# skip duplicates
while left < right and nums[left] == nums[left + 1]:
left += 1
while left < right and nums[right] == nums[right - 1]:
right -= 1
# shift pointers
left += 1
right -= 1
# since sorted, if current < target, then move left
elif current < target:
left += 1
# since sorted, if current > target, then move right
else:
right -= 1
return result
```
@@ -37,27 +37,19 @@ Your solution must use only constant extra space.
## Solution
```js
/**
* @param {number[]} numbers
* @param {number} target
* @return {number[]}
*/
var twoSum = function(numbers, target) {
let i = 0, j = numbers.length - 1;
```py
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
i = 0
j = len(numbers) - 1
while (i < j) {
const curr = numbers[i] + numbers[j];
if (curr === target){
return [i + 1, j + 1];
}else{
if (curr < target){
i++;
}else{
j--;
}
}
}
return [];
};
while i < j:
c = numbers[i] + numbers[j]
if c == target:
return [i + 1, j + 1]
elif c < target:
i+=1
else:
j-=1
return []
```
@@ -0,0 +1,44 @@
---
title: '392. Is Subsequence'
description: Given two strings s and t, return true if s is a subsequence of t, or false otherwise
sidebar:
label: 'Is Subsequence'
badge: 'Easy'
---
<Badge variant="accent">Two Pointers</Badge>
::::warning
Suppose there are lots of incoming s, say s1, s2, ..., sk where k >= 10^9, and you want to check one by one to see if t has its subsequence. In this scenario, how would you change your code?
::::
### Example 1:
- Input: `s = "abc", t = "ahbgdc"`
- Output: `true`
### Example 2:
- Input: `s = "axc", t = "ahbgdc"`
- Output: `false`
### Constraints:
- `0 <= s.length <= 100`
- `0 <= t.length <= 10^4`
- `s` and `t` consist only of lowercase English letters.
## Solution
```py
class Solution:
def isSubsequence(self, s: str, t: str) -> bool:
if len(s) > len(t):
return False
i, j = 0, 0
while i < len(s) and j < len(t):
if s[i] == t[j]:
i += 1
j += 1
return i == len(s)
```
+1
View File
@@ -6,6 +6,7 @@
"dev": "blume dev",
"build": "blume build",
"doctor": "blume doctor",
"close-solved": "bun scripts/close-solved.ts",
"pick": "bun scripts/pick.ts",
"sync": "bun scripts/sync.ts",
"test": "bun scripts/test.ts"
+275
View File
@@ -0,0 +1,275 @@
#!/usr/bin/env bun
/**
* Close the GitHub issue for every LeetCode problem actually solved under work/.
*
* Reconciles state instead of reacting to a push diff: any `problem`-labelled
* issue whose LC number has an *implemented* solution file in work/ gets
* closed. Only open issues are touched, so re-runs are no-ops and backfilling
* needs no special casing. Removing a solution never reopens an issue.
*
* `bun run pick` scaffolds a statement header plus an empty function body, so
* file existence alone means nothing — a stub must not close its issue. See
* isImplemented().
*
* bun scripts/close-solved.ts # close matches
* bun scripts/close-solved.ts --dry-run # report only, touch nothing
*
* Auth: GH_TOKEN / GITHUB_TOKEN, else falls back to `gh auth token`.
*/
import { $ } from "bun";
import { basename, join } from "node:path";
const ROOT = join(import.meta.dir, "..");
const WORK = join(ROOT, "work");
const DRY =
process.argv.includes("--dry-run") ||
process.env.DRY_RUN === "1" ||
process.env.DRY_RUN === "true";
// ── is the file a real solution or just a scaffolded stub? ────────
/** Placeholder bodies that leetcode-cli / a human leaves behind. */
const PLACEHOLDERS: Record<string, true> = { pass: true, "...": true, TODO: true };
/**
* Decide whether a work/ file contains an implementation.
*
* The header comment is dropped the same way sync.ts splitSource() does it
* (duplicated rather than imported, because sync.ts runs its whole pipeline on
* import). Comments must go before any brace analysis: the scaffold's JSDoc
* carries `@param {number[]}`, whose braces would otherwise read as a body.
*
* A brace-language file counts as implemented when at least one *innermost*
* brace pair holds real content. That distinguishes a bare stub
* (`function(nums) {}`) and a class-shaped design stub (every method body
* empty) from any genuine solution, whose innermost block always has code.
*/
function isImplemented(src: string, lang: "js" | "py"): boolean {
if (lang === "py") {
const open = src.indexOf('"""');
const close = src.indexOf('"""', open + 3);
const code = open === -1 || close === -1 ? src : src.slice(close + 3);
for (const raw of code.split("\n")) {
const line = raw.replace(/#.*$/, "").trim();
if (!line || PLACEHOLDERS[line]) continue;
if (/^(?:@|def\s|class\s)/.test(line)) continue;
return true; // a statement inside some def body
}
return false;
}
const headerEnd = src.indexOf("*/");
const body = headerEnd === -1 ? src : src.slice(headerEnd + 2);
const code = body.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/\/\/.*$/gm, " ");
let innermost = -1;
for (let i = 0; i < code.length; i++) {
if (code[i] === "{") {
innermost = i;
} else if (code[i] === "}" && innermost !== -1) {
const inner = code.slice(innermost + 1, i).replace(/[\s;]/g, "");
if (inner && !PLACEHOLDERS[inner]) return true;
innermost = -1; // measured; the enclosing pair is not innermost
}
}
return false;
}
// ── repo + auth ──────────────────────────────────────────────────
async function resolveRepo(): Promise<string> {
if (process.env.GITHUB_REPOSITORY) return process.env.GITHUB_REPOSITORY;
const url = (await $`git -C ${ROOT} remote get-url origin`.text()).trim();
const m = url.match(/github\.com[:/](.+?)(?:\.git)?$/);
if (!m) throw new Error(`cannot derive owner/repo from remote: ${url}`);
return m[1]!;
}
async function resolveToken(): Promise<string> {
const env = process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
if (env) return env;
const token = (await $`gh auth token`.text()).trim();
if (!token) throw new Error("no credentials: set GH_TOKEN or run `gh auth login`");
return token;
}
const repo = await resolveRepo();
const token = await resolveToken();
async function api(path: string, init: RequestInit = {}): Promise<unknown> {
const res = await fetch(`https://api.github.com${path}`, {
...init,
headers: {
accept: "application/vnd.github+json",
authorization: `Bearer ${token}`,
"x-github-api-version": "2022-11-28",
...(init.body ? { "content-type": "application/json" } : {}),
},
});
if (!res.ok) {
throw new Error(`${init.method ?? "GET"} ${path} -> ${res.status} ${await res.text()}`);
}
return res.json();
}
// ── work/ inventory ──────────────────────────────────────────────
interface WorkEntry {
files: string[];
implemented: boolean;
}
/** LC number -> solution files (a problem may have both js and py). */
const work = new Map<number, WorkEntry>();
for await (const rel of new Bun.Glob("**/*.{js,py}").scan(WORK)) {
const m = basename(rel).match(/^(\d+)\.(.+)\.(?:js|py)$/);
if (!m) {
console.warn(`skip (unrecognized name): work/${rel}`);
continue;
}
const num = Number(m[1]);
const src = await Bun.file(join(WORK, rel)).text();
const implemented = isImplemented(src, rel.endsWith(".py") ? "py" : "js");
const entry = work.get(num);
if (entry) {
entry.files.push(`work/${rel}`);
entry.implemented ||= implemented;
} else {
work.set(num, { files: [`work/${rel}`], implemented });
}
}
// ── open problem issues ──────────────────────────────────────────
interface ProblemIssue {
number: number;
set: string;
}
/**
* Narrow one element of the /issues payload to the fields this script needs.
* Returns undefined for pull requests and for anything whose title is not a
* `LC <num> ...` problem, which is how non-curriculum rows get skipped.
*/
function readProblemIssue(
value: unknown,
): { lc: number; issue: ProblemIssue } | undefined {
if (!value || typeof value !== "object") return;
if ("pull_request" in value) return; // the /issues route also lists PRs
if (!("number" in value) || typeof value.number !== "number") return;
if (!("title" in value) || typeof value.title !== "string") return;
const lc = value.title.match(/^LC (\d+) /);
if (!lc) return;
let set = "—";
if ("labels" in value && Array.isArray(value.labels)) {
for (const label of value.labels) {
if (
label &&
typeof label === "object" &&
"name" in label &&
typeof label.name === "string" &&
label.name.startsWith("set:")
) {
set = label.name;
}
}
}
return { lc: Number(lc[1]), issue: { number: value.number, set } };
}
/** LC number -> open issue carrying the `problem` label. */
const open = new Map<number, ProblemIssue>();
for (let page = 1; ; page++) {
const batch = await api(
`/repos/${repo}/issues?labels=problem&state=open&per_page=100&page=${page}`,
);
if (!Array.isArray(batch)) throw new Error("unexpected /issues payload: not an array");
for (const raw of batch) {
const parsed = readProblemIssue(raw);
if (parsed) open.set(parsed.lc, parsed.issue);
}
if (batch.length < 100) break;
}
// ── reconcile ────────────────────────────────────────────────────
const sha = process.env.GITHUB_SHA;
const report: string[][] = [];
let closed = 0;
for (const num of [...work.keys()].sort((a, b) => a - b)) {
const entry = work.get(num)!;
const issue = open.get(num);
// Warm-ups and out-of-curriculum practice have no issue. Not an error.
if (!issue) {
report.push([`${num}`, "—", "—", "no open issue"]);
continue;
}
if (!entry.implemented) {
report.push([`${num}`, `#${issue.number}`, issue.set, "stub — skipped"]);
continue;
}
if (DRY) {
report.push([`${num}`, `#${issue.number}`, issue.set, "would close"]);
continue;
}
const links = entry.files
.map((f) =>
sha ? `[\`${f}\`](https://github.com/${repo}/blob/${sha}/${encodeURI(f)})` : `\`${f}\``,
)
.join(", ");
await api(`/repos/${repo}/issues/${issue.number}/comments`, {
method: "POST",
body: JSON.stringify({
body:
`Solved — solution committed at ${links}.\n\n` +
"Closed automatically by `close-solved`. Fill in the close-out block above if you have not already.",
}),
});
await api(`/repos/${repo}/issues/${issue.number}`, {
method: "PATCH",
body: JSON.stringify({ state: "closed", state_reason: "completed" }),
});
report.push([`${num}`, `#${issue.number}`, issue.set, "closed"]);
closed++;
}
// ── report ───────────────────────────────────────────────────────
const rows = [["lc", "issue", "set", "status"], ...report];
const widths = rows[0]!.map((_, i) => Math.max(...rows.map((r) => r[i]!.length)));
const rendered = rows.map((r) =>
r
.map((cell, i) => cell.padEnd(widths[i]!))
.join(" ")
.trimEnd(),
);
console.log(rendered[0]);
console.log(widths.map((n) => "─".repeat(n)).join(" "));
for (const row of rendered.slice(1)) console.log(row);
const implemented = [...work.values()].filter((e) => e.implemented).length;
const actionable = report.filter((r) => r[3] !== "no open issue");
console.log(
`\n${work.size} in work/ · ${implemented} implemented · ` +
`${actionable.length} matched an open issue · ` +
`${DRY ? `would close ${actionable.filter((r) => r[3] === "would close").length}` : `closed ${closed}`}`,
);
if (process.env.GITHUB_STEP_SUMMARY) {
const body = actionable.map((r) => `| ${r[0]} | ${r[1]} | ${r[2]} | ${r[3]} |`).join("\n");
await Bun.write(
process.env.GITHUB_STEP_SUMMARY,
`### close-solved${DRY ? " (dry run)" : ""}\n\n` +
`${work.size} files in \`work/\`, ${implemented} implemented, ` +
`${actionable.length} matched an open issue.\n\n` +
(body
? `| LC | Issue | Set | Status |\n| --- | --- | --- | --- |\n${body}\n`
: "Nothing to close.\n"),
);
}
+60
View File
@@ -0,0 +1,60 @@
"""
1. Two Sum
Difficulty: Easy
https://leetcode.com/problems/two-sum/
──────────────────────────────────────────────────
You are given an array of integers nums and an integer target, return
indices of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and
you may not use the same element twice.
You can return the answer in any order.
Example 1:
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].
Example 2:
Input: nums = [3,2,4], target = 6
Output: [1,2]
Example 3:
Input: nums = [3,3], target = 6
Output: [0,1]
Constraints:
• 2 <= nums.length <= 10^4
• -10^9 <= nums[i] <= 10^9
• -10^9 <= target <= 10^9
• Only one valid answer exists.
Follow-up: Can you come up with an algorithm that is less than O(n^2)
time complexity?
"""
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
seen = {}
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i
return []
@@ -0,0 +1,57 @@
"""
392. Is Subsequence
Difficulty: Easy
https://leetcode.com/problems/is-subsequence/
──────────────────────────────────────────────────
Given two strings s and t, return true if s is a subsequence of t, or
false otherwise.
A subsequence of a string is a new string that is formed from the
original string by deleting some (can be none) of the characters
without disturbing the relative positions of the remaining characters.
(i.e., "ace" is a subsequence of "abcde" while "aec" is not).
Example 1:
Input: s = "abc", t = "ahbgdc"
Output: true
Example 2:
Input: s = "axc", t = "ahbgdc"
Output: false
Constraints:
• 0 <= s.length <= 100
• 0 <= t.length <= 10^4
• s and t consist only of lowercase English letters.
Follow up: Suppose there are lots of incoming s, say s1, s2, ..., sk
where k >= 10^9, and you want to check one by one to see if t has its
subsequence. In this scenario, how would you change your code?
"""
class Solution:
def isSubsequence(self, s: str, t: str) -> bool:
if len(s) > len(t):
return False
i, j = 0, 0
while i < len(s) and j < len(t):
if s[i] == t[j]:
i += 1
j += 1
return i == len(s)
@@ -0,0 +1,60 @@
"""
11. Container With Most Water
Difficulty: Medium
https://leetcode.com/problems/container-with-most-water/
──────────────────────────────────────────────────
You are given an integer array height of length n. There are n
vertical lines drawn such that the two endpoints of the i^th line are
(i, 0) and (i, height[i]).
Find two lines that together with the x-axis form a container, such
that the container contains the most water.
Return the maximum amount of water a container can store.
Notice that you may not slant the container.
Example 1:
Input: height = [1,8,6,2,5,4,8,3,7]
Output: 49
Explanation: The above vertical lines are represented by array
[1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue
section) the container can contain is 49.
Example 2:
Input: height = [1,1]
Output: 1
Constraints:
• n == height.length
• 2 <= n <= 10^5
• 0 <= height[i] <= 10^4
"""
class Solution:
def maxArea(self, height: List[int]) -> int: # noqa: F821
res = 0
left = 0
right = len(height) - 1
while left < right:
area = (right - left) * min(height[left], height[right])
res = max(res, area)
if height[left] < height[right]:
left += 1
else:
right -= 1
return res
-55
View File
@@ -1,55 +0,0 @@
/*
* 15. 3Sum
* Difficulty: Medium
* https://leetcode.com/problems/3sum/
*
* ──────────────────────────────────────────────────
*
* Given an integer array nums, return all the triplets [nums[i],
* nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] +
* nums[j] + nums[k] == 0.
*
* Notice that the solution set must not contain duplicate triplets.
*
*
*
* Example 1:
*
* Input: nums = [-1,0,1,2,-1,-4]
* Output: [[-1,-1,2],[-1,0,1]]
* Explanation:
* nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0.
* nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0.
* nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0.
* The distinct triplets are [-1,0,1] and [-1,-1,2].
* Notice that the order of the output and the order of the triplets
* does not matter.
*
* Example 2:
*
* Input: nums = [0,1,1]
* Output: []
* Explanation: The only possible triplet does not sum up to 0.
*
* Example 3:
*
* Input: nums = [0,0,0]
* Output: [[0,0,0]]
* Explanation: The only possible triplet sums up to 0.
*
*
*
* Constraints:
*
* • 3 <= nums.length <= 3000
*
* • -10^5 <= nums[i] <= 10^5
*/
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
};
+89
View File
@@ -0,0 +1,89 @@
"""
15. 3Sum
Difficulty: Medium
https://leetcode.com/problems/3sum/
──────────────────────────────────────────────────
Given an integer array nums, return all the triplets [nums[i],
nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] +
nums[j] + nums[k] == 0.
Notice that the solution set must not contain duplicate triplets.
Example 1:
Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]
Explanation:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0.
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0.
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0.
The distinct triplets are [-1,0,1] and [-1,-1,2].
Notice that the order of the output and the order of the triplets
does not matter.
Example 2:
Input: nums = [0,1,1]
Output: []
Explanation: The only possible triplet does not sum up to 0.
Example 3:
Input: nums = [0,0,0]
Output: [[0,0,0]]
Explanation: The only possible triplet sums up to 0.
Constraints:
• 3 <= nums.length <= 3000
• -10^5 <= nums[i] <= 10^5
"""
class Solution:
def threeSum(self, nums: list[int]) -> list[list[int]]:
nums.sort()
result = []
n = len(nums)
for i in range(n):
# skip all zero
if i > 0 and nums[i] == nums[i - 1]:
continue
# two pointers
left = i + 1
right = n - 1
target = -nums[i]
while left < right:
current = nums[left] + nums[right]
if current == target:
result.append([nums[i], nums[left], nums[right]])
# skip duplicates
while left < right and nums[left] == nums[left + 1]:
left += 1
while left < right and nums[right] == nums[right - 1]:
right -= 1
# shift pointers
left += 1
right -= 1
# since sorted, if current < target, then move left
elif current < target:
left += 1
# since sorted, if current > target, then move right
else:
right -= 1
return result
@@ -1,80 +0,0 @@
/*
* 167. Two Sum II - Input Array Is Sorted
* Difficulty: Medium
* https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/
*
* ──────────────────────────────────────────────────
*
* Given a 1-indexed array of integers numbers that is already sorted in
* non-decreasing order, find two numbers such that they add up to a
* specific target number. Let these two numbers be numbers[index1] and
* numbers[index2] where 1 <= index1 < index2 <= numbers.length.
*
* Return the indices of the two numbers index1 and index2, each
* incremented by one, as an integer array [index1, index2] of length 2.
*
* The tests are generated such that there is exactly one solution. You
* may not use the same element twice.
*
* Your solution must use only constant extra space.
*
*
*
* Example 1:
*
* Input: numbers = [2,7,11,15], target = 9
* Output: [1,2]
* Explanation: The sum of 2 and 7 is 9. Therefore, index1 = 1, index2 =
* 2. We return [1, 2].
*
* Example 2:
*
* Input: numbers = [2,3,4], target = 6
* Output: [1,3]
* Explanation: The sum of 2 and 4 is 6. Therefore index1 = 1, index2 =
* 3. We return [1, 3].
*
* Example 3:
*
* Input: numbers = [-1,0], target = -1
* Output: [1,2]
* Explanation: The sum of -1 and 0 is -1. Therefore index1 = 1, index2
* = 2. We return [1, 2].
*
*
*
* Constraints:
*
* • 2 <= numbers.length <= 3 * 10^4
*
* • -1000 <= numbers[i] <= 1000
*
* • numbers is sorted in non-decreasing order.
*
* • -1000 <= target <= 1000
*
* • The tests are generated such that there is exactly one solution.
*/
/**
* @param {number[]} numbers
* @param {number} target
* @return {number[]}
*/
var twoSum = function(numbers, target) {
let i = 0, j = numbers.length - 1;
while (i < j) {
const curr = numbers[i] + numbers[j];
if (curr === target){
return [i + 1, j + 1];
}else{
if (curr < target){
i++;
}else{
j--;
}
}
}
return [];
};
@@ -0,0 +1,73 @@
"""
167. Two Sum II - Input Array Is Sorted
Difficulty: Medium
https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/
──────────────────────────────────────────────────
Given a 1-indexed array of integers numbers that is already sorted in
non-decreasing order, find two numbers such that they add up to a
specific target number. Let these two numbers be numbers[index1] and
numbers[index2] where 1 <= index1 < index2 <= numbers.length.
Return the indices of the two numbers index1 and index2, each
incremented by one, as an integer array [index1, index2] of length 2.
The tests are generated such that there is exactly one solution. You
may not use the same element twice.
Your solution must use only constant extra space.
Example 1:
Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: The sum of 2 and 7 is 9. Therefore, index1 = 1, index2 =
2. We return [1, 2].
Example 2:
Input: numbers = [2,3,4], target = 6
Output: [1,3]
Explanation: The sum of 2 and 4 is 6. Therefore index1 = 1, index2 =
3. We return [1, 3].
Example 3:
Input: numbers = [-1,0], target = -1
Output: [1,2]
Explanation: The sum of -1 and 0 is -1. Therefore index1 = 1, index2
= 2. We return [1, 2].
Constraints:
• 2 <= numbers.length <= 3 * 10^4
• -1000 <= numbers[i] <= 1000
• numbers is sorted in non-decreasing order.
• -1000 <= target <= 1000
• The tests are generated such that there is exactly one solution.
"""
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
i = 0
j = len(numbers) - 1
while i < j:
c = numbers[i] + numbers[j]
if c == target:
return [i + 1, j + 1]
elif c < target:
i+=1
else:
j-=1
return []
-57
View File
@@ -1,57 +0,0 @@
/*
* 189. Rotate Array
* Difficulty: Medium
* https://leetcode.com/problems/rotate-array/
*
* ──────────────────────────────────────────────────
*
* Given an integer array nums, rotate the array to the right by k
* steps, where k is non-negative.
*
*
*
* Example 1:
*
* Input: nums = [1,2,3,4,5,6,7], k = 3
* Output: [5,6,7,1,2,3,4]
* Explanation:
* rotate 1 steps to the right: [7,1,2,3,4,5,6]
* rotate 2 steps to the right: [6,7,1,2,3,4,5]
* rotate 3 steps to the right: [5,6,7,1,2,3,4]
*
* Example 2:
*
* Input: nums = [-1,-100,3,99], k = 2
* Output: [3,99,-1,-100]
* Explanation:
* rotate 1 steps to the right: [99,-1,-100,3]
* rotate 2 steps to the right: [3,99,-1,-100]
*
*
*
* Constraints:
*
* • 1 <= nums.length <= 10^5
*
* • -2^31 <= nums[i] <= 2^31 - 1
*
* • 0 <= k <= 10^5
*
*
*
* Follow up:
*
* • Try to come up with as many solutions as you can. There are at
* least three different ways to solve this problem.
*
* • Could you do it in-place with O(1) extra space?
*/
/**
* @param {number[]} nums
* @param {number} k
* @return {void} Do not return anything, modify nums in-place instead.
*/
var rotate = function(nums, k) {
};
@@ -1,79 +0,0 @@
/*
* 2090. K Radius Subarray Averages
* Difficulty: Medium
* https://leetcode.com/problems/k-radius-subarray-averages/
*
* ──────────────────────────────────────────────────
*
* You are given a 0-indexed array nums of n integers, and an integer k.
*
* The k-radius average for a subarray of nums centered at some index i
* with the radius k is the average of all elements in nums between the
* indices i - k and i + k (inclusive). If there are less than k elements
* before or after the index i, then the k-radius average is -1.
*
* Build and return an array avgs of length n where avgs[i] is the
* k-radius average for the subarray centered at index i.
*
* The average of x elements is the sum of the x elements divided by x,
* using integer division. The integer division truncates toward zero,
* which means losing its fractional part.
*
* • For example, the average of four elements 2, 3, 1, and 5 is (2 + 3
* + 1 + 5) / 4 = 11 / 4 = 2.75, which truncates to 2.
*
*
*
* Example 1:
*
* Input: nums = [7,4,3,9,1,8,5,2,6], k = 3
* Output: [-1,-1,-1,5,4,4,-1,-1,-1]
* Explanation:
* - avg[0], avg[1], and avg[2] are -1 because there are less than k
* elements before each index.
* - The sum of the subarray centered at index 3 with radius 3 is: 7 + 4
* + 3 + 9 + 1 + 8 + 5 = 37.
* Using integer division, avg[3] = 37 / 7 = 5.
* - For the subarray centered at index 4, avg[4] = (4 + 3 + 9 + 1 + 8 +
* 5 + 2) / 7 = 4.
* - For the subarray centered at index 5, avg[5] = (3 + 9 + 1 + 8 + 5 +
* 2 + 6) / 7 = 4.
* - avg[6], avg[7], and avg[8] are -1 because there are less than k
* elements after each index.
*
* Example 2:
*
* Input: nums = [100000], k = 0
* Output: [100000]
* Explanation:
* - The sum of the subarray centered at index 0 with radius 0 is:
* 100000.
* avg[0] = 100000 / 1 = 100000.
*
* Example 3:
*
* Input: nums = [8], k = 100000
* Output: [-1]
* Explanation:
* - avg[0] is -1 because there are less than k elements before and
* after index 0.
*
*
*
* Constraints:
*
* • n == nums.length
*
* • 1 <= n <= 10^5
*
* • 0 <= nums[i], k <= 10^5
*/
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var getAverages = function(nums, k) {
};