Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
abcbdc8
Add IntelliJ IDEA run configurations to gitignore and JUnit launcher …
yamcodes Feb 10, 2026
5d18af7
Merge branch 'main' into 18-improve-minimum-deletions-space-complexit…
yamcodes Feb 10, 2026
1fe4740
Add solution progression to package-info and stub O(1) DP solution
yamcodes Feb 12, 2026
0ef02a2
Refactor solution links to use code tags for clarity
yamcodes Feb 12, 2026
87750a9
Update solution progression to reflect new implementations
yamcodes Feb 12, 2026
d6a3ef0
Refactor solution progression documentation and add naive and prefix/…
yamcodes Feb 12, 2026
e00ba3d
Refactor: Rename solution classes and update references
yamcodes Feb 13, 2026
c874624
Refactor solution file naming and test structure
yamcodes Feb 13, 2026
0ebe23f
Refactor Test run configuration encoding
yamcodes Feb 13, 2026
bebf22e
Rename test run configuration to "Test All"
yamcodes Feb 13, 2026
808d20e
Implement space-optimized DP solution for minimum deletions
yamcodes Feb 14, 2026
dccc212
Refactor minimumDeletions to simplify logic and improve clarity
yamcodes Feb 14, 2026
3022aaf
Refactor variable initialization for clarity
yamcodes Feb 14, 2026
357059e
Disable unused test classes and reorder variables in Solution.java
yamcodes Feb 14, 2026
4d737f4
Add TODO to refactor Solution with cleaner DP formulation
yamcodes Feb 14, 2026
ae5de78
Update TODO comment for DP implementation in minimum deletions
yamcodes Feb 14, 2026
9916c30
Add climbing stairs solution and test cases
yamcodes Feb 14, 2026
d825814
Merge branch 'main' into climbing-stairs
yamcodes Feb 14, 2026
6a031ed
Clarify `@ValueSource` and `@MethodSource` usage in README.md
yamcodes Feb 14, 2026
7d0add9
Disable climbing stairs tests until implementation is complete
yamcodes Feb 14, 2026
9ff2fde
Implement recursive solution for climbing stairs problem
yamcodes Feb 14, 2026
d910277
Implement memoized solution for climbing stairs problem
yamcodes Feb 14, 2026
bfb216e
Add base cases for n=1 and n=2 to memoized solution
yamcodes Feb 14, 2026
9fc6b12
Initialize memoization array as a class member
yamcodes Feb 14, 2026
ab1871c
Implement dynamic programming solution for climbing stairs
yamcodes Feb 14, 2026
5de63dd
Make Solution class public and adjust loop start index
yamcodes Feb 14, 2026
2a6cb8a
Add Climbing Stairs to README
yamcodes Feb 14, 2026
f747d7e
Refactor Solution to O(1) space complexity
yamcodes Feb 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,14 @@ src/test/java/codes/yam/leetcode/{problemslug}/

Each test file uses `@MethodSource("fully.qualified.TestCases#cases")` to share test data.

**When to use `@ValueSource` vs `@MethodSource`:** Use `@ValueSource` for single-argument problems with groupable
outcomes (e.g., boolean results — group inputs by true/false). Use `@MethodSource` with `TestCases` when each input has
a distinct expected output (e.g., `climbStairs(3) → 3`).

## Code Conventions

**Solution classes** are package-scoped (not `public`), use prefix naming (`Solution`, `SolutionNaive`, `SolutionDp`, etc.), and use HTML-formatted Javadoc:
**Solution classes** are package-scoped (not `public`), use prefix naming (`Solution`, `SolutionNaive`, `SolutionDp`,
etc.), and use HTML-formatted Javadoc:

```java
/**
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ My LeetCode solutions in Java, focused on clean code and optimal algorithms.
|------|-----------------------------------------------------------------------------------------------------------------------|------------|-------------------|--------|
| 1 | [Two Sum](https://leetcode.com/problems/two-sum/) | Easy | `O(n log n)` | `O(n)` |
| 9 | [Palindrome Number](https://leetcode.com/problems/palindrome-number/) | Easy | `O(log10(n) / 2)` | `O(1)` |
| 70 | [Climbing Stairs](https://leetcode.com/problems/climbing-stairs/) | Easy | `O(n)` | `O(1)` |
| 1653 | [Minimum Deletions to Make String Balanced](https://leetcode.com/problems/minimum-deletions-to-make-string-balanced/) | Medium | `O(n)` | `O(1)` |

## Project Structure
Expand All @@ -29,7 +30,8 @@ src/test/java/codes/yam/leetcode/{problem-slug}/
```

When a problem has multiple solution approaches, each gets its own `Solution*.java` class. `Solution.java` is always the
optimal/final version. The progression is documented in `package-info.java`. Test data lives in a shared `TestCases.java`,
optimal/final version. The progression is documented in `package-info.java`. Test data lives in a shared
`TestCases.java`,
and each solution has its own test file using `@MethodSource` to reference it.

## Commands
Expand All @@ -51,7 +53,8 @@ Right-click `src/test/java/codes/yam/leetcode/` → **New → Package** → `pro

Start with LeetCode's example cases plus a few edge cases (aim for 3–5 per behavior):

**For single-arg problems** — use `@ValueSource`, grouped by expected outcome:
**For single-argument problems with groupable outcomes** (e.g., boolean results — group inputs by true/false) — use
`@ValueSource`:

```java
class SolutionTest {
Expand All @@ -71,7 +74,7 @@ class SolutionTest {
}
```

**For multi-arg problems** — use `@MethodSource`:
**When each input has a distinct expected output** (e.g., `climbStairs(3) → 3`) — use `@MethodSource` with `TestCases`:

```java
class SolutionTest {
Expand Down
61 changes: 61 additions & 0 deletions src/main/java/codes/yam/leetcode/climbingstairs/NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Recursion to DP: Step by Step

## Starting point: your memoized solution

```java
int rec(int n) {
if (n == 1) return 1;
if (n == 2) return 2;
if (memo[n] != 0) return memo[n];
memo[n] = rec(n - 1) + rec(n - 2);
return memo[n];
}
```

## Steps to convert to bottom-up DP

1. **Look at what the memo array stores.** Each `memo[i]` holds the answer for input `i`. That's your DP table.

2. **Find the base cases.** These are the entries you can fill without recursion: `memo[1] = 1` and `memo[2] = 2`.

3. **Find the recurrence.** Strip away the recursion and just look at the formula:
`memo[n] = memo[n - 1] + memo[n - 2]`.

4. **Figure out the fill order.** `memo[i]` depends on `memo[i - 1]` and `memo[i - 2]` — both smaller. So fill from
small to large (3, 4, 5, ... n).

5. **Write the loop.** Seed the base cases, then loop from 3 to n applying the recurrence.

## Result

```java
int climbStairs(int n) {
if (n <= 2) return n;
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
```

## Bonus: space optimization

Notice `dp[i]` only ever reads `dp[i - 1]` and `dp[i - 2]`. You don't need the whole array — just two variables.

```java
int climbStairs(int n) {
if (n <= 2) return n;
int prev2 = 1, prev1 = 2;
for (int i = 3; i <= n; i++) {
int curr = prev1 + prev2;
prev2 = prev1;
prev1 = curr;
}
return prev1;
}
```

This drops space from O(n) to O(1).
27 changes: 27 additions & 0 deletions src/main/java/codes/yam/leetcode/climbingstairs/Solution.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package codes.yam.leetcode.climbingstairs;

/**
* Solution for the <b>Climbing Stairs</b> problem.
*
* <p>Optimizes {@code SolutionDp} by replacing the DP array with two rolling variables.
*
* <ul>
* <li><b>Time Complexity:</b> <code>O(n)</code>
* <li><b>Space Complexity:</b> <code>O(1)</code>
* </ul>
*/
class Solution {
int climbStairs(int n) {
if (n == 1) return 1;
if (n == 2) return 2;
int a = 1;
int b = 2;
int c = a + b;
for (int i = 3; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return c;
}
}
22 changes: 22 additions & 0 deletions src/main/java/codes/yam/leetcode/climbingstairs/SolutionDp.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package codes.yam.leetcode.climbingstairs;

/**
* Solution for the <b>Climbing Stairs</b> problem.
*
* <ul>
* <li><b>Time Complexity:</b> <code>O(n)</code>
* <li><b>Space Complexity:</b> <code>O(n)</code>
* </ul>
*/
class SolutionDp {
int climbStairs(int n) {
if (n <= 2) return n;
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package codes.yam.leetcode.climbingstairs;

/**
* Solution for the <b>Climbing Stairs</b> problem.
*
* <ul>
* <li><b>Time Complexity:</b> <code>O(n)</code>
* <li><b>Space Complexity:</b> <code>O(n)</code>
* </ul>
*/
class SolutionMemoized {
int[] memo;

int rec(int n) {
if (n == 1) return 1;
if (n == 2) return 2;
if (memo[n] == 0) {
memo[n] = rec(n - 1) + rec(n - 2);
}
return memo[n];
}

int climbStairs(int n) {
memo = new int[n + 1];
return rec(n);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package codes.yam.leetcode.climbingstairs;

/**
* Solution for the <b>Climbing Stairs</b> problem.
*
* <ul>
* <li><b>Time Complexity:</b> <code>O(2^n)</code>
* <li><b>Space Complexity:</b> <code>O(n)</code>
* </ul>
*/
class SolutionRecursive {
int climbStairs(int n) {
if (n == 1) return 1;
if (n == 2) return 2;
return climbStairs(n - 1) + climbStairs(n - 2);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package codes.yam.leetcode.climbingstairs;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

class SolutionDpTest {
@ParameterizedTest
@MethodSource("codes.yam.leetcode.climbingstairs.TestCases#cases")
void climbStairs(int n, int expected) {
assertEquals(expected, new SolutionDp().climbStairs(n));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package codes.yam.leetcode.climbingstairs;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

class SolutionMemoizedTest {
@ParameterizedTest
@MethodSource("codes.yam.leetcode.climbingstairs.TestCases#cases")
void climbStairs(int n, int expected) {
assertEquals(expected, new SolutionMemoized().climbStairs(n));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package codes.yam.leetcode.climbingstairs;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

class SolutionRecursiveTest {
@ParameterizedTest
@MethodSource("codes.yam.leetcode.climbingstairs.TestCases#cases")
void climbStairs(int n, int expected) {
assertEquals(expected, new SolutionRecursive().climbStairs(n));
}
}
14 changes: 14 additions & 0 deletions src/test/java/codes/yam/leetcode/climbingstairs/SolutionTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package codes.yam.leetcode.climbingstairs;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

class SolutionTest {
@ParameterizedTest
@MethodSource("codes.yam.leetcode.climbingstairs.TestCases#cases")
void climbStairs(int n, int expected) {
assertEquals(expected, new Solution().climbStairs(n));
}
}
11 changes: 11 additions & 0 deletions src/test/java/codes/yam/leetcode/climbingstairs/TestCases.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package codes.yam.leetcode.climbingstairs;

import java.util.stream.Stream;
import org.junit.jupiter.params.provider.Arguments;

@SuppressWarnings("unused")
class TestCases {
static Stream<Arguments> cases() {
return Stream.of(Arguments.of(2, 2), Arguments.of(3, 3));
}
}