mirror of
https://github.com/prdlk/leetcode.git
synced 2026-11-02 21:22:43 +00:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b5879b6eb | ||
|
|
53136b076c | ||
|
|
95f10980d4 | ||
|
|
c6ecb85507 | ||
|
|
2a69f36e6a | ||
|
|
5e4628b20f | ||
|
|
72a8399e6d | ||
|
|
6ebca68ff8 | ||
|
|
957ddf9849 | ||
|
|
e67cc79f39 | ||
|
|
f086c2b39a |
No files matched your search
@@ -49,8 +49,10 @@ All from the repo root (a Bun workspace over `apps/*`):
|
||||
bun run pick # scaffold a solution via leetcode-cli (fuzzy picker; hides problems
|
||||
# already under work/, caches index+descriptions in
|
||||
# ~/.local/share/leetcode/data.db — see apps/cli/db.ts)
|
||||
bun run test # run ONE solution against LeetCode's judge (not a test suite)
|
||||
bun run submit # submit ONE solution to LeetCode (same picker as test)
|
||||
bun run test # run ONE solution against LeetCode's judge (not a test suite;
|
||||
# most recently tested first, stamped in the db on exit 0)
|
||||
bun run submit # submit ONE solution to LeetCode (newest scaffold first, nothing
|
||||
# hidden; last_submitted stamped in the db on exit 0)
|
||||
bun run sync # work/ → apps/docs/content/ pages
|
||||
bun run dev|build # Blume docs site (runs in apps/docs/)
|
||||
bun run close-solved -- --dry-run # issue reconcilers (also DRY_RUN=1)
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
addDays,
|
||||
campaignDay,
|
||||
campaignWeek,
|
||||
isoWeek,
|
||||
streak,
|
||||
} from "./srs.ts";
|
||||
|
||||
@@ -61,9 +62,14 @@ export async function buildStats(db: D1Database, today: string): Promise<object>
|
||||
const ladder: Record<string, number> = { new: 0, "+2": 0, "+5": 0, "+10": 0, retired: 0 };
|
||||
for (const row of ladderRows) ladder[row.stage] = row.n;
|
||||
|
||||
const { results: gates } = await db
|
||||
// gates rows are keyed by ISO week (that's the digest/gate contract), but
|
||||
// the page speaks campaign weeks. The campaign never crosses a year
|
||||
// boundary, so a plain offset converts safely.
|
||||
const isoWeekOffset = isoWeek(CAMPAIGN_START) - 1;
|
||||
const { results: gateRows } = await db
|
||||
.prepare("SELECT week, issue, pass_rate, closed_on FROM gates ORDER BY week")
|
||||
.all<{ week: number; issue: number | null; pass_rate: number | null; closed_on: string | null }>();
|
||||
const gates = gateRows.map((g) => ({ ...g, week: g.week - isoWeekOffset }));
|
||||
|
||||
// Review-queue depth for the next 14 days: everything due by that day.
|
||||
const queue: { date: string; due: number }[] = [];
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
* are ever fetched, and paid-only problems are skipped because GraphQL
|
||||
* returns null content for them.
|
||||
*
|
||||
* A `solutions` table tracks the lifecycle of each work/ file by LC number:
|
||||
* `created_at` (backfilled from the file's birthtime on every picker run),
|
||||
* `last_tested` and `last_submitted` (stamped on exit 0 of leetcode-cli).
|
||||
* The test picker sorts by last_tested, the submit picker by created_at, and
|
||||
* submit hides anything with a last_submitted.
|
||||
*
|
||||
* Library: side-effect-free on import — nothing is opened or fetched until
|
||||
* problemDb() is called. Index upserts never touch the description column, so
|
||||
* a daily refresh cannot evict cached statements.
|
||||
@@ -27,6 +33,13 @@ export interface Problem {
|
||||
paidOnly: boolean;
|
||||
}
|
||||
|
||||
/** Lifecycle of one work/ solution, keyed by LC number. ISO timestamps. */
|
||||
export interface SolutionActivity {
|
||||
createdAt: string;
|
||||
lastTested: string | null;
|
||||
lastSubmitted: string | null;
|
||||
}
|
||||
|
||||
const DIFFICULTY = ["", "Easy", "Medium", "Hard"] as const;
|
||||
const INDEX_TTL_MS = 24 * 60 * 60 * 1000;
|
||||
|
||||
@@ -109,6 +122,13 @@ export function problemDb(path = DB_PATH) {
|
||||
paid_only INTEGER NOT NULL,
|
||||
description TEXT
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS solutions (
|
||||
id INTEGER PRIMARY KEY,
|
||||
created_at TEXT NOT NULL,
|
||||
last_tested TEXT,
|
||||
last_submitted TEXT
|
||||
);
|
||||
DROP TABLE IF EXISTS submissions;
|
||||
CREATE TABLE IF NOT EXISTS meta (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
@@ -177,6 +197,37 @@ export function problemDb(path = DB_PATH) {
|
||||
db.query("UPDATE problems SET description = ?2 WHERE slug = ?1").run(slug, html);
|
||||
},
|
||||
|
||||
/** Per-solution lifecycle rows keyed by LC number. */
|
||||
solutionActivity(): Map<number, SolutionActivity> {
|
||||
const rows = db
|
||||
.query<{ id: number; created_at: string; last_tested: string | null; last_submitted: string | null }, []>(
|
||||
"SELECT id, created_at, last_tested, last_submitted FROM solutions",
|
||||
)
|
||||
.all();
|
||||
return new Map(
|
||||
rows.map((r) => [r.id, { createdAt: r.created_at, lastTested: r.last_tested, lastSubmitted: r.last_submitted }]),
|
||||
);
|
||||
},
|
||||
|
||||
/** Register a solution's creation time; existing rows are left alone. */
|
||||
ensureSolution(id: number, createdAt: string): void {
|
||||
db.query("INSERT INTO solutions (id, created_at) VALUES (?1, ?2) ON CONFLICT(id) DO NOTHING").run(id, createdAt);
|
||||
},
|
||||
|
||||
markTested(id: number): void {
|
||||
db.query(
|
||||
`INSERT INTO solutions (id, created_at, last_tested) VALUES (?1, ?2, ?2)
|
||||
ON CONFLICT(id) DO UPDATE SET last_tested = excluded.last_tested`,
|
||||
).run(id, new Date().toISOString());
|
||||
},
|
||||
|
||||
markSubmitted(id: number): void {
|
||||
db.query(
|
||||
`INSERT INTO solutions (id, created_at, last_submitted) VALUES (?1, ?2, ?2)
|
||||
ON CONFLICT(id) DO UPDATE SET last_submitted = excluded.last_submitted`,
|
||||
).run(id, new Date().toISOString());
|
||||
},
|
||||
|
||||
close(): void {
|
||||
db.close();
|
||||
},
|
||||
|
||||
+59
-6
@@ -1,18 +1,64 @@
|
||||
/**
|
||||
* Shared work/ solution picker for the test and submit entries: fuzzy-select
|
||||
* a solution file, then hand it to leetcode-cli. Library: side-effect-free on
|
||||
* import — nothing scans the filesystem until runOnSolution() is called.
|
||||
* a solution file, then hand it to leetcode-cli.
|
||||
*
|
||||
* Every run backfills the db's solutions table with created_at (from the
|
||||
* file's birthtime, mtime when the filesystem has none) so ordering works for
|
||||
* files that predate the db. Ordering is per command — test lists the most
|
||||
* recently tested first (never-tested after, by name); submit lists the most
|
||||
* recently created first. Nothing is ever hidden. Exit 0 of leetcode-cli
|
||||
* stamps last_tested / last_submitted.
|
||||
*
|
||||
* Library: side-effect-free on import — nothing scans the filesystem until
|
||||
* runOnSolution() is called.
|
||||
*/
|
||||
import { autocomplete, cancel, isCancel, log } from "@clack/prompts";
|
||||
import { join, relative } from "node:path";
|
||||
import { statSync } from "node:fs";
|
||||
import { basename, join, relative } from "node:path";
|
||||
import { problemDb } from "./db";
|
||||
|
||||
const ROOT = join(import.meta.dir, "..", "..");
|
||||
const WORK_DIR = join(ROOT, "work");
|
||||
|
||||
/** Leading LC number of a work/ file, or undefined for unnumbered names. */
|
||||
function lcNumber(rel: string): number | undefined {
|
||||
const m = basename(rel).match(/^(\d+)\./);
|
||||
return m ? Number(m[1]) : undefined;
|
||||
}
|
||||
|
||||
/** Fuzzy-pick a solution under work/ and run `leetcode <command>` on it. */
|
||||
export async function runOnSolution(command: "test" | "submit", message: string): Promise<never> {
|
||||
const files = [...new Bun.Glob("**/*.{js,ts,py,java,c,cpp,go,rs,rb,swift,kt,cs}").scanSync({ cwd: WORK_DIR })]
|
||||
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
||||
const db = problemDb();
|
||||
|
||||
const scanned = [...new Bun.Glob("**/*.{js,ts,py,java,c,cpp,go,rs,rb,swift,kt,cs}").scanSync({ cwd: WORK_DIR })];
|
||||
|
||||
// register creation times so files older than the db still sort correctly
|
||||
for (const f of scanned) {
|
||||
const num = lcNumber(f);
|
||||
if (num === undefined) continue;
|
||||
const stat = statSync(join(WORK_DIR, f));
|
||||
db.ensureSolution(num, new Date(stat.birthtimeMs || stat.mtimeMs).toISOString());
|
||||
}
|
||||
const activity = db.solutionActivity();
|
||||
|
||||
// test → most recently tested first; submit → most recently created first
|
||||
const sortKey = (f: string) => {
|
||||
const num = lcNumber(f);
|
||||
const row = num === undefined ? undefined : activity.get(num);
|
||||
return (command === "test" ? row?.lastTested : row?.createdAt) ?? undefined;
|
||||
};
|
||||
|
||||
const files = scanned
|
||||
.sort((a, b) => {
|
||||
const ka = sortKey(a);
|
||||
const kb = sortKey(b);
|
||||
if (ka !== kb) {
|
||||
if (ka === undefined) return 1;
|
||||
if (kb === undefined) return -1;
|
||||
return kb.localeCompare(ka); // ISO timestamps: lexicographic = chronological
|
||||
}
|
||||
return a.localeCompare(b, undefined, { numeric: true });
|
||||
});
|
||||
|
||||
if (files.length === 0) {
|
||||
log.error(`No solution files found in ${relative(process.cwd(), WORK_DIR)}/`);
|
||||
@@ -55,5 +101,12 @@ export async function runOnSolution(command: "test" | "submit", message: string)
|
||||
],
|
||||
{ cwd: ROOT, stdio: ["inherit", "inherit", "inherit"] },
|
||||
);
|
||||
process.exit(await proc.exited);
|
||||
const code = await proc.exited;
|
||||
const num = lcNumber(picked);
|
||||
if (code === 0 && num !== undefined) {
|
||||
if (command === "test") db.markTested(num);
|
||||
else db.markSubmitted(num);
|
||||
}
|
||||
db.close();
|
||||
process.exit(code);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
title: '150. Evaluate Reverse Polish Notation'
|
||||
description: You are given an array of strings tokens that represents an arithmetic expression in a Reverse Polish Notation
|
||||
sidebar:
|
||||
label: 'Evaluate Reverse Polish Notation'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Stack</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `tokens = ["2","1","+","3","*"]`
|
||||
- Output: `9`
|
||||
- Explanation: `((2 + 1`) * `3`) = `9`
|
||||
|
||||
### Example 2:
|
||||
- Input: `tokens = ["4","13","5","/","+"]`
|
||||
- Output: `6`
|
||||
- Explanation: `(4 + (13 / 5`)) = `6`
|
||||
|
||||
### Example 3:
|
||||
- Input: `tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]`
|
||||
- Output: `22`
|
||||
- Explanation: `((10 * (6 / ((9 + 3`) * `-11`))) + `17`) + `5 = ((10 * (6 / (12 * -11`))) + `17`) + `5 = ((10 * (6 / -132`)) + `17`) + `5 = ((10 * 0`) + `17`) + `5 = (0 + 17`) + `5 = 17 + 5 = 22`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= tokens.length <= 10^4`
|
||||
- `tokens[i]` is either an operator: "+", "-", "*", or "/", or an integer in the range [-200, 200].
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def evalRPN(self, tokens: List[str]) -> int:
|
||||
stack = []
|
||||
operations = {
|
||||
"+": lambda x, y: int(x + y),
|
||||
"-": lambda x, y: int(x - y),
|
||||
"*": lambda x, y: int(x * y),
|
||||
"/": lambda x, y: int(x / y),
|
||||
}
|
||||
|
||||
for c in tokens:
|
||||
if c in operations:
|
||||
y = stack.pop()
|
||||
x = stack.pop()
|
||||
calc_func = operations[c]
|
||||
result = calc_func(x, y)
|
||||
stack.append(result)
|
||||
else:
|
||||
stack.append(int(c))
|
||||
|
||||
return stack[0]
|
||||
```
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
title: '153. Find Minimum in Rotated Sorted Array'
|
||||
description: 'Suppose an array of length n sorted in ascending order is rotated between 1 and n times. For example, the array nums = [0,1,2,4,5,6,7] might become:'
|
||||
sidebar:
|
||||
label: 'Find Minimum in Rotated Sorted Array'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Binary Search</Badge>
|
||||
|
||||
::::warning
|
||||
Notice that rotating an array [a[0], a[1], a[2], ..., a[n-1]] 1 time results in the array [a[n-1], a[0], a[1], a[2], ..., a[n-2]].
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [3,4,5,1,2]`
|
||||
- Output: `1`
|
||||
- Explanation: The original array was `[1,2,3,4,5]` rotated `3` times.
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [4,5,6,7,0,1,2]`
|
||||
- Output: `0`
|
||||
- Explanation: The original array was `[0,1,2,4,5,6,7]` and it was rotated `4` times.
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [11,13,15,17]`
|
||||
- Output: `11`
|
||||
- Explanation: The original array was `[11,13,15,17]` and it was rotated `4` times.
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `n == nums.length`
|
||||
- `1 <= n <= 5000`
|
||||
- `-5000 <= nums[i] <= 5000`
|
||||
- All the integers of `nums` are unique.
|
||||
- `nums` is sorted and rotated between 1 and `n` times.
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def findMin(self, nums: List[int]) -> int:
|
||||
l, r = 0, len(nums) - 1
|
||||
lowest_index = -1
|
||||
|
||||
while l <= r:
|
||||
m = (l + r) // 2
|
||||
if nums[m] <= nums[-1]:
|
||||
lowest_index = m
|
||||
r = m - 1
|
||||
else:
|
||||
l = m + 1
|
||||
|
||||
return nums[lowest_index]
|
||||
```
|
||||
@@ -1,42 +0,0 @@
|
||||
---
|
||||
title: '189. Rotate Array'
|
||||
description: Given an integer array nums, rotate the array to the right by k steps, where k is non-negative
|
||||
sidebar:
|
||||
label: 'Rotate Array'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Two Pointers</Badge>
|
||||
|
||||
::::warning
|
||||
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?
|
||||
::::
|
||||
|
||||
### 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`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @param {number} k
|
||||
* @return {void} Do not return anything, modify nums in-place instead.
|
||||
*/
|
||||
var rotate = function(nums, k) {
|
||||
|
||||
};
|
||||
```
|
||||
@@ -1,50 +0,0 @@
|
||||
---
|
||||
title: '2090. K Radius Subarray Averages'
|
||||
description: You are given a 0-indexed array nums of n integers, and an integer k
|
||||
sidebar:
|
||||
label: 'K Radius Subarray Averages'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Array</Badge>
|
||||
|
||||
### 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`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @param {number} k
|
||||
* @return {number[]}
|
||||
*/
|
||||
var getAverages = function(nums, k) {
|
||||
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: '35. Search Insert Position'
|
||||
description: Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order
|
||||
sidebar:
|
||||
label: 'Search Insert Position'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Binary Search</Badge>
|
||||
|
||||
::::warning
|
||||
You must write an algorithm with O(log n) runtime complexity.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: `nums = [1,3,5,6], target = 5`
|
||||
- Output: `2`
|
||||
|
||||
### Example 2:
|
||||
- Input: `nums = [1,3,5,6], target = 2`
|
||||
- Output: `1`
|
||||
|
||||
### Example 3:
|
||||
- Input: `nums = [1,3,5,6], target = 7`
|
||||
- Output: `4`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= nums.length <= 10^4`
|
||||
- `-10^4 <= nums[i] <= 10^4`
|
||||
- `nums` contains distinct values sorted in ascending order.
|
||||
- `-10^4 <= target <= 10^4`
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def searchInsert(self, nums: List[int], target: int) -> int:
|
||||
l, r = 0, len(nums) - 1
|
||||
|
||||
while l <= r:
|
||||
m = (l + r) // 2
|
||||
if nums[m] == target:
|
||||
return m
|
||||
elif nums[m] < target:
|
||||
l = m + 1
|
||||
elif nums[m] > target:
|
||||
r = m - 1
|
||||
|
||||
return (l + r) // 2 + 1
|
||||
```
|
||||
@@ -1,36 +0,0 @@
|
||||
---
|
||||
title: '42. Trapping Rain Water'
|
||||
description: Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining
|
||||
sidebar:
|
||||
label: 'Trapping Rain Water'
|
||||
badge: 'Hard'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Two Pointers</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `height = [0,1,0,2,1,0,1,3,2,1,2,1]`
|
||||
- Output: `6`
|
||||
- Explanation: The above elevation map (black section) is represented by array `[0,1,0,2,1,0,1,3,2,1,2,1]`. In this case, `6` units of rain water (blue section) are being trapped.
|
||||
|
||||
### Example 2:
|
||||
- Input: `height = [4,2,0,3,2,5]`
|
||||
- Output: `9`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `n == height.length`
|
||||
- `1 <= n <= 2 * 10^4`
|
||||
- `0 <= height[i] <= 10^5`
|
||||
|
||||
## Solution
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} height
|
||||
* @return {number}
|
||||
*/
|
||||
var trap = function(height) {
|
||||
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
title: '155. Min Stack'
|
||||
description: Design a stack that supports push, pop, top, and retrieving the minimum element in constant time
|
||||
sidebar:
|
||||
label: 'Min Stack'
|
||||
badge: 'Medium'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Stack</Badge>
|
||||
|
||||
::::warning
|
||||
You must implement a solution with O(1) time complexity for each function.
|
||||
::::
|
||||
|
||||
### Example 1:
|
||||
- Input: ``
|
||||
- Output: ``
|
||||
- Explanation: Input `["MinStack","push","push","push","getMin","pop","top","getMin"]` [[],[-2],[0],[-3],[],[],[],[]] Output `[null,null,null,null,-3,null,0,-2]` Explanation MinStack minStack = new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); minStack.getMin(); // return `-3` minStack.pop(); minStack.top(); // return `0` minStack.getMin(); // return `-2`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `-2^31 <= val <= 2^31 - 1`
|
||||
- Methods pop, top and getMin operations will always be called on non-empty stacks.
|
||||
- At most 3 * 10^4 calls will be made to push, pop, top, and getMin.
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class MinStack:
|
||||
def __init__(self):
|
||||
self.stack = []
|
||||
self.minStack = []
|
||||
|
||||
def push(self, value: int) -> None:
|
||||
self.stack.append(value)
|
||||
value = min(value, self.minStack[-1] if self.minStack else value)
|
||||
self.minStack.append(value)
|
||||
|
||||
def pop(self) -> None:
|
||||
self.stack.pop()
|
||||
self.minStack.pop()
|
||||
|
||||
def top(self) -> int:
|
||||
return self.stack[-1]
|
||||
|
||||
def getMin(self) -> int:
|
||||
return self.minStack[-1]
|
||||
|
||||
|
||||
# Your MinStack object will be instantiated and called as such:
|
||||
# obj = MinStack()
|
||||
# obj.push(value)
|
||||
# obj.pop()
|
||||
# param_3 = obj.top()
|
||||
# param_4 = obj.getMin()
|
||||
```
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: '20. Valid Parentheses'
|
||||
description: Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid
|
||||
sidebar:
|
||||
label: 'Valid Parentheses'
|
||||
badge: 'Easy'
|
||||
---
|
||||
|
||||
<Badge variant="accent">Stack</Badge>
|
||||
|
||||
### Example 1:
|
||||
- Input: `s = "()"`
|
||||
- Output: `true`
|
||||
|
||||
### Example 2:
|
||||
- Input: `s = "()[]{}"`
|
||||
- Output: `true`
|
||||
|
||||
### Example 3:
|
||||
- Input: `s = "(]"`
|
||||
- Output: `false`
|
||||
|
||||
### Example 4:
|
||||
- Input: `s = "([])"`
|
||||
- Output: `true`
|
||||
|
||||
### Example 5:
|
||||
- Input: `s = "([)]"`
|
||||
- Output: `false`
|
||||
|
||||
### Constraints:
|
||||
|
||||
- `1 <= s.length <= 10^4`
|
||||
- `s` consists of parentheses only '()[]{}'.
|
||||
|
||||
## Solution
|
||||
|
||||
```py
|
||||
class Solution:
|
||||
def isValid(self, s: str) -> bool:
|
||||
stack = []
|
||||
pairs = {")": "(", "]": "[", "}": "{"}
|
||||
|
||||
for c in s:
|
||||
if c in pairs:
|
||||
if stack and pairs[c] == stack[-1]:
|
||||
stack.pop()
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
stack.append(c)
|
||||
|
||||
return True if not stack else False
|
||||
```
|
||||
@@ -35,6 +35,7 @@ interface Stats {
|
||||
deferred_total: number;
|
||||
}[];
|
||||
ladder: Record<Stage, number>;
|
||||
/** week is the 1-based campaign week — the Worker converts from ISO. */
|
||||
gates: {
|
||||
week: number;
|
||||
issue: number | null;
|
||||
@@ -76,7 +77,12 @@ function dayLabel(iso: string): string {
|
||||
return `${weekday} ${iso.slice(8)}`;
|
||||
}
|
||||
|
||||
// ── shared styles (theme tokens only — no hand-rolled palette) ───
|
||||
// ── shared styles ────────────────────────────────────────────────
|
||||
// Theme tokens only, with two deliberate exceptions: the phase-bar sets get
|
||||
// fixed hues (accent-blue core, yellow optional, red deferred — they must be
|
||||
// distinguishable, not shades of one colour), and the last-7-days heatmap
|
||||
// reuses the GREENS ramp from apps/api/src/charts.ts so the page matches the
|
||||
// README/email heatmaps (level 0 stays a theme token so light mode works).
|
||||
|
||||
const card: CSSProperties = {
|
||||
border: "1px solid var(--blume-border)",
|
||||
@@ -142,32 +148,78 @@ function Header({ stats }: { stats: Stats }) {
|
||||
);
|
||||
}
|
||||
|
||||
// One stacked bar per phase: solved core / optional / deferred segments over
|
||||
// a muted track sized by the phase's total problem count, so both phase size
|
||||
// and progress read at a glance.
|
||||
const SETS = [
|
||||
["core", "var(--blume-accent)"],
|
||||
["optional", "#d29922"],
|
||||
["deferred", "#e5534b"],
|
||||
] as const;
|
||||
|
||||
function Phases({ stats }: { stats: Stats }) {
|
||||
const maxTotal = Math.max(
|
||||
1,
|
||||
...stats.phases.map((p) => p.core_total + p.optional_total + p.deferred_total),
|
||||
);
|
||||
return (
|
||||
<div style={card}>
|
||||
<div style={heading}>Phases</div>
|
||||
<table style={{ borderCollapse: "collapse", width: "100%" }}>
|
||||
<tbody>
|
||||
{stats.phases.map((p) => (
|
||||
<tr key={p.milestone}>
|
||||
<td style={{ padding: "0.2rem 1rem 0.2rem 0" }}>{p.name}</td>
|
||||
<td style={{ padding: "0.2rem 1rem 0.2rem 0" }}>
|
||||
<Bar done={p.core_done} total={p.core_total} />{" "}
|
||||
<span style={muted}>
|
||||
core {p.core_done}/{p.core_total}
|
||||
</span>
|
||||
</td>
|
||||
<td style={{ padding: "0.2rem 0" }}>
|
||||
<span style={muted}>
|
||||
optional {p.optional_done}/{p.optional_total}
|
||||
{p.deferred_total > 0 &&
|
||||
` · deferred ${p.deferred_done}/${p.deferred_total}`}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<div style={{ display: "flex", gap: "1rem", flexWrap: "wrap", marginBottom: "0.6rem" }}>
|
||||
{SETS.map(([set, color]) => (
|
||||
<span key={set} style={muted}>
|
||||
<span
|
||||
style={{
|
||||
display: "inline-block",
|
||||
width: "0.65rem",
|
||||
height: "0.65rem",
|
||||
borderRadius: "2px",
|
||||
background: color,
|
||||
marginRight: "0.35rem",
|
||||
}}
|
||||
/>
|
||||
{set}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
{stats.phases.map((p) => {
|
||||
const total = p.core_total + p.optional_total + p.deferred_total;
|
||||
const done = p.core_done + p.optional_done + p.deferred_done;
|
||||
return (
|
||||
<div
|
||||
key={p.milestone}
|
||||
title={`core ${p.core_done}/${p.core_total} · optional ${p.optional_done}/${p.optional_total} · deferred ${p.deferred_done}/${p.deferred_total}`}
|
||||
style={{ display: "flex", alignItems: "center", gap: "0.75rem", padding: "0.25rem 0" }}
|
||||
>
|
||||
<span style={{ width: "9.5rem", flexShrink: 0 }}>{p.name}</span>
|
||||
<span style={{ flex: 1 }}>
|
||||
<span
|
||||
style={{
|
||||
display: "flex",
|
||||
width: `${(total / maxTotal) * 100}%`,
|
||||
height: "0.65rem",
|
||||
borderRadius: "var(--blume-radius)",
|
||||
background: "var(--blume-muted)",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{SETS.map(([set, color]) => {
|
||||
const solved = p[`${set}_done`];
|
||||
return solved > 0 ? (
|
||||
<span
|
||||
key={set}
|
||||
style={{ width: `${(solved / total) * 100}%`, background: color }}
|
||||
/>
|
||||
) : null;
|
||||
})}
|
||||
</span>
|
||||
</span>
|
||||
<span style={{ ...muted, width: "3.5rem", textAlign: "right", flexShrink: 0 }}>
|
||||
{done}/{total}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -224,76 +276,95 @@ function Gates({ stats }: { stats: Stats }) {
|
||||
<div style={card}>
|
||||
<div style={heading}>Gate log</div>
|
||||
{stats.gates.length === 0 ? (
|
||||
<span style={muted}>No gates yet.</span>
|
||||
<span style={muted}>No gates yet — the first weekly review opens Saturday night.</span>
|
||||
) : (
|
||||
<table style={{ borderCollapse: "collapse", width: "100%" }}>
|
||||
<thead>
|
||||
<tr>
|
||||
{["Week", "Issue", "Pass rate", "Closed"].map((h) => (
|
||||
<th key={h} style={{ ...muted, textAlign: "left", padding: "0.2rem 1rem 0.2rem 0" }}>
|
||||
{h}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{stats.gates.map((g) => (
|
||||
<tr key={g.week}>
|
||||
<td style={{ padding: "0.2rem 1rem 0.2rem 0" }}>{g.week}</td>
|
||||
<td style={{ padding: "0.2rem 1rem 0.2rem 0" }}>
|
||||
{g.issue === null ? (
|
||||
<span style={muted}>—</span>
|
||||
) : (
|
||||
<a
|
||||
href={`https://github.com/prdlk/leetcode/issues/${g.issue}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
#{g.issue}
|
||||
</a>
|
||||
)}
|
||||
</td>
|
||||
<td style={{ padding: "0.2rem 1rem 0.2rem 0" }}>
|
||||
{g.pass_rate === null ? (
|
||||
<span style={muted}>open</span>
|
||||
) : (
|
||||
percent(g.pass_rate)
|
||||
)}
|
||||
</td>
|
||||
<td style={{ padding: "0.2rem 0" }}>
|
||||
{g.closed_on ?? <span style={muted}>—</span>}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
stats.gates.map((g) => (
|
||||
<div
|
||||
key={g.week}
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: "0.75rem",
|
||||
alignItems: "baseline",
|
||||
flexWrap: "wrap",
|
||||
padding: "0.15rem 0",
|
||||
}}
|
||||
>
|
||||
<span style={{ width: "4.5rem", flexShrink: 0 }}>Week {g.week}</span>
|
||||
{g.issue === null ? (
|
||||
<span style={muted}>no review issue</span>
|
||||
) : (
|
||||
<a
|
||||
href={`https://github.com/prdlk/leetcode/issues/${g.issue}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
#{g.issue}
|
||||
</a>
|
||||
)}
|
||||
{g.pass_rate === null ? (
|
||||
<span style={muted}>in progress</span>
|
||||
) : (
|
||||
<span>
|
||||
{percent(g.pass_rate)} passed
|
||||
{g.closed_on && <span style={muted}> · closed {g.closed_on}</span>}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
<div style={{ ...muted, marginTop: "0.4rem" }}>
|
||||
One gate per campaign week — scored when its review issue closes.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// GREENS ramp from apps/api/src/charts.ts; level 0 swapped for the theme's
|
||||
// muted token so an empty day looks right in both colour schemes.
|
||||
const GREENS = [
|
||||
"var(--blume-muted)",
|
||||
"#0e4429",
|
||||
"#006d32",
|
||||
"#26a641",
|
||||
"#39d353",
|
||||
];
|
||||
|
||||
function Recent({ stats }: { stats: Stats }) {
|
||||
return (
|
||||
<div style={card}>
|
||||
<div style={heading}>Last 7 days</div>
|
||||
<div style={{ display: "flex", gap: "0.5rem", flexWrap: "wrap" }}>
|
||||
<div style={{ display: "flex", gap: "0.4rem", flexWrap: "wrap" }}>
|
||||
{stats.recent.map((r) => (
|
||||
<span
|
||||
key={r.date}
|
||||
style={{
|
||||
border: "1px solid var(--blume-border)",
|
||||
borderRadius: "var(--blume-radius)",
|
||||
padding: "0.35rem 0.6rem",
|
||||
textAlign: "center",
|
||||
}}
|
||||
title={`${r.date}: ${r.passes}/${r.attempts} passed`}
|
||||
style={{ textAlign: "center" }}
|
||||
>
|
||||
<span style={{ ...muted, display: "block" }}>{dayLabel(r.date)}</span>
|
||||
<strong>{r.passes}</strong>
|
||||
<span style={muted}>/{r.attempts}</span>
|
||||
<span
|
||||
style={{
|
||||
display: "block",
|
||||
width: "2.6rem",
|
||||
height: "2rem",
|
||||
borderRadius: "var(--blume-radius)",
|
||||
background: GREENS[Math.min(r.attempts, 4)],
|
||||
}}
|
||||
/>
|
||||
<span style={{ ...muted, display: "block", marginTop: "0.25rem", fontSize: "0.75em" }}>
|
||||
{dayLabel(r.date)}
|
||||
</span>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div style={{ ...muted, marginTop: "0.4rem" }}>passes / attempts</div>
|
||||
<div style={{ ...muted, marginTop: "0.5rem", display: "flex", alignItems: "center", gap: "0.25rem" }}>
|
||||
<span>Less</span>
|
||||
{GREENS.map((color) => (
|
||||
<span
|
||||
key={color}
|
||||
style={{ display: "inline-block", width: "0.65rem", height: "0.65rem", borderRadius: "2px", background: color }}
|
||||
/>
|
||||
))}
|
||||
<span>More · colour = attempts, hover for passes</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
"""
|
||||
35. Search Insert Position
|
||||
Difficulty: Easy
|
||||
https://leetcode.com/problems/search-insert-position/
|
||||
|
||||
──────────────────────────────────────────────────
|
||||
|
||||
Given a sorted array of distinct integers and a target value, return
|
||||
the index if the target is found. If not, return the index where it
|
||||
would be if it were inserted in order.
|
||||
|
||||
You must write an algorithm with O(log n) runtime complexity.
|
||||
|
||||
|
||||
|
||||
Example 1:
|
||||
|
||||
Input: nums = [1,3,5,6], target = 5
|
||||
Output: 2
|
||||
|
||||
Example 2:
|
||||
|
||||
Input: nums = [1,3,5,6], target = 2
|
||||
Output: 1
|
||||
|
||||
Example 3:
|
||||
|
||||
Input: nums = [1,3,5,6], target = 7
|
||||
Output: 4
|
||||
|
||||
|
||||
|
||||
Constraints:
|
||||
|
||||
• 1 <= nums.length <= 10^4
|
||||
|
||||
• -10^4 <= nums[i] <= 10^4
|
||||
|
||||
• nums contains distinct values sorted in ascending order.
|
||||
|
||||
• -10^4 <= target <= 10^4
|
||||
"""
|
||||
|
||||
|
||||
class Solution:
|
||||
def searchInsert(self, nums: List[int], target: int) -> int:
|
||||
l, r = 0, len(nums) - 1
|
||||
|
||||
while l <= r:
|
||||
m = (l + r) // 2
|
||||
if nums[m] == target:
|
||||
return m
|
||||
elif nums[m] < target:
|
||||
l = m + 1
|
||||
elif nums[m] > target:
|
||||
r = m - 1
|
||||
|
||||
return (l + r) // 2 + 1
|
||||
@@ -0,0 +1,76 @@
|
||||
"""
|
||||
20. Valid Parentheses
|
||||
Difficulty: Easy
|
||||
https://leetcode.com/problems/valid-parentheses/
|
||||
|
||||
──────────────────────────────────────────────────
|
||||
|
||||
Given a string s containing just the characters '(', ')', '{', '}',
|
||||
'[' and ']', determine if the input string is valid.
|
||||
|
||||
An input string is valid if:
|
||||
|
||||
• Open brackets must be closed by the same type of brackets.
|
||||
|
||||
• Open brackets must be closed in the correct order.
|
||||
|
||||
• Every close bracket has a corresponding open bracket of the same
|
||||
type.
|
||||
|
||||
|
||||
|
||||
Example 1:
|
||||
|
||||
Input: s = "()"
|
||||
|
||||
Output: true
|
||||
|
||||
Example 2:
|
||||
|
||||
Input: s = "()[]{}"
|
||||
|
||||
Output: true
|
||||
|
||||
Example 3:
|
||||
|
||||
Input: s = "(]"
|
||||
|
||||
Output: false
|
||||
|
||||
Example 4:
|
||||
|
||||
Input: s = "([])"
|
||||
|
||||
Output: true
|
||||
|
||||
Example 5:
|
||||
|
||||
Input: s = "([)]"
|
||||
|
||||
Output: false
|
||||
|
||||
|
||||
|
||||
Constraints:
|
||||
|
||||
• 1 <= s.length <= 10^4
|
||||
|
||||
• s consists of parentheses only '()[]{}'.
|
||||
"""
|
||||
|
||||
|
||||
class Solution:
|
||||
def isValid(self, s: str) -> bool:
|
||||
stack = []
|
||||
pairs = {")": "(", "]": "[", "}": "{"}
|
||||
|
||||
for c in s:
|
||||
if c in pairs:
|
||||
if stack and pairs[c] == stack[-1]:
|
||||
stack.pop()
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
stack.append(c)
|
||||
|
||||
return True if not stack else False
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 42. Trapping Rain Water
|
||||
* Difficulty: Hard
|
||||
* https://leetcode.com/problems/trapping-rain-water/
|
||||
*
|
||||
* ──────────────────────────────────────────────────
|
||||
*
|
||||
* Given n non-negative integers representing an elevation map where the
|
||||
* width of each bar is 1, compute how much water it can trap after
|
||||
* raining.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Example 1:
|
||||
*
|
||||
* Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
|
||||
* Output: 6
|
||||
* Explanation: The above elevation map (black section) is represented
|
||||
* by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain
|
||||
* water (blue section) are being trapped.
|
||||
*
|
||||
* Example 2:
|
||||
*
|
||||
* Input: height = [4,2,0,3,2,5]
|
||||
* Output: 9
|
||||
*
|
||||
*
|
||||
*
|
||||
* Constraints:
|
||||
*
|
||||
* • n == height.length
|
||||
*
|
||||
* • 1 <= n <= 2 * 10^4
|
||||
*
|
||||
* • 0 <= height[i] <= 10^5
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {number[]} height
|
||||
* @return {number}
|
||||
*/
|
||||
var trap = function(height) {
|
||||
|
||||
};
|
||||
@@ -0,0 +1,88 @@
|
||||
"""
|
||||
150. Evaluate Reverse Polish Notation
|
||||
Difficulty: Medium
|
||||
https://leetcode.com/problems/evaluate-reverse-polish-notation/
|
||||
|
||||
──────────────────────────────────────────────────
|
||||
|
||||
You are given an array of strings tokens that represents an
|
||||
arithmetic expression in a Reverse Polish Notation.
|
||||
|
||||
Evaluate the expression. Return an integer that represents the value
|
||||
of the expression.
|
||||
|
||||
Note that:
|
||||
|
||||
• The valid operators are '+', '-', '*', and '/'.
|
||||
|
||||
• Each operand may be an integer or another expression.
|
||||
|
||||
• The division between two integers always truncates toward zero.
|
||||
|
||||
• There will not be any division by zero.
|
||||
|
||||
• The input represents a valid arithmetic expression in a reverse
|
||||
polish notation.
|
||||
|
||||
• The answer and all the intermediate calculations can be
|
||||
represented in a 32-bit integer.
|
||||
|
||||
|
||||
|
||||
Example 1:
|
||||
|
||||
Input: tokens = ["2","1","+","3","*"]
|
||||
Output: 9
|
||||
Explanation: ((2 + 1) * 3) = 9
|
||||
|
||||
Example 2:
|
||||
|
||||
Input: tokens = ["4","13","5","/","+"]
|
||||
Output: 6
|
||||
Explanation: (4 + (13 / 5)) = 6
|
||||
|
||||
Example 3:
|
||||
|
||||
Input: tokens =
|
||||
["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
|
||||
Output: 22
|
||||
Explanation: ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
|
||||
= ((10 * (6 / (12 * -11))) + 17) + 5
|
||||
= ((10 * (6 / -132)) + 17) + 5
|
||||
= ((10 * 0) + 17) + 5
|
||||
= (0 + 17) + 5
|
||||
= 17 + 5
|
||||
= 22
|
||||
|
||||
|
||||
|
||||
Constraints:
|
||||
|
||||
• 1 <= tokens.length <= 10^4
|
||||
|
||||
• tokens[i] is either an operator: "+", "-", "*", or "/", or an
|
||||
integer in the range [-200, 200].
|
||||
"""
|
||||
|
||||
|
||||
class Solution:
|
||||
def evalRPN(self, tokens: List[str]) -> int:
|
||||
stack = []
|
||||
operations = {
|
||||
"+": lambda x, y: int(x + y),
|
||||
"-": lambda x, y: int(x - y),
|
||||
"*": lambda x, y: int(x * y),
|
||||
"/": lambda x, y: int(x / y),
|
||||
}
|
||||
|
||||
for c in tokens:
|
||||
if c in operations:
|
||||
y = stack.pop()
|
||||
x = stack.pop()
|
||||
calc_func = operations[c]
|
||||
result = calc_func(x, y)
|
||||
stack.append(result)
|
||||
else:
|
||||
stack.append(int(c))
|
||||
|
||||
return stack[0]
|
||||
@@ -0,0 +1,86 @@
|
||||
"""
|
||||
155. Min Stack
|
||||
Difficulty: Medium
|
||||
https://leetcode.com/problems/min-stack/
|
||||
|
||||
──────────────────────────────────────────────────
|
||||
|
||||
Design a stack that supports push, pop, top, and retrieving the
|
||||
minimum element in constant time.
|
||||
|
||||
Implement the MinStack class:
|
||||
|
||||
• MinStack() initializes the stack object.
|
||||
|
||||
• void push(int value) pushes the element value onto the stack.
|
||||
|
||||
• void pop() removes the element on the top of the stack.
|
||||
|
||||
• int top() gets the top element of the stack.
|
||||
|
||||
• int getMin() retrieves the minimum element in the stack.
|
||||
|
||||
You must implement a solution with O(1) time complexity for each
|
||||
function.
|
||||
|
||||
|
||||
|
||||
Example 1:
|
||||
|
||||
Input
|
||||
["MinStack","push","push","push","getMin","pop","top","getMin"]
|
||||
[[],[-2],[0],[-3],[],[],[],[]]
|
||||
|
||||
Output
|
||||
[null,null,null,null,-3,null,0,-2]
|
||||
|
||||
Explanation
|
||||
MinStack minStack = new MinStack();
|
||||
minStack.push(-2);
|
||||
minStack.push(0);
|
||||
minStack.push(-3);
|
||||
minStack.getMin(); // return -3
|
||||
minStack.pop();
|
||||
minStack.top(); // return 0
|
||||
minStack.getMin(); // return -2
|
||||
|
||||
|
||||
|
||||
Constraints:
|
||||
|
||||
• -2^31 <= val <= 2^31 - 1
|
||||
|
||||
• Methods pop, top and getMin operations will always be called on
|
||||
non-empty stacks.
|
||||
|
||||
• At most 3 * 10^4 calls will be made to push, pop, top, and getMin.
|
||||
"""
|
||||
|
||||
|
||||
class MinStack:
|
||||
def __init__(self):
|
||||
self.stack = []
|
||||
self.minStack = []
|
||||
|
||||
def push(self, value: int) -> None:
|
||||
self.stack.append(value)
|
||||
value = min(value, self.minStack[-1] if self.minStack else value)
|
||||
self.minStack.append(value)
|
||||
|
||||
def pop(self) -> None:
|
||||
self.stack.pop()
|
||||
self.minStack.pop()
|
||||
|
||||
def top(self) -> int:
|
||||
return self.stack[-1]
|
||||
|
||||
def getMin(self) -> int:
|
||||
return self.minStack[-1]
|
||||
|
||||
|
||||
# Your MinStack object will be instantiated and called as such:
|
||||
# obj = MinStack()
|
||||
# obj.push(value)
|
||||
# obj.pop()
|
||||
# param_3 = obj.top()
|
||||
# param_4 = obj.getMin()
|
||||
Reference in new issue
Block a user