Unique Paths (LeetCode 62)
There is a robot on an
m x ngrid. The robot is initially located at the top-left corner (i.e.,grid[0][0]). The robot tries to move to the bottom-right corner (i.e.,grid[m - 1][n - 1]). The robot can only move either down or right at any point in time.Given the two integers
mandn, return the number of possible unique paths that the robot can take to reach the bottom-right corner.The test cases are generated so that the answer will be less than or equal to
2 * 109.
Example 1:

Input: m = 3, n = 7
Output: 28
Example 2:
Input: m = 3, n = 2
Output: 3
Explanation: From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
- Right -> Down -> Down
- Down -> Down -> Right
- Down -> Right -> Down
class Solution {
public int uniquePaths(int m, int n) {
int dp[][] = new int[m][n];
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(i==0 || j==0){
dp[i][j] = 1;
}else{
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
}
return dp[m-1][n-1];
}
}class Solution:
def uniquePaths(self, m: int, n: int) -> int:
dp = [[1] * n for _ in range(m)]
for i in range(1, m):
for j in range(1, n):
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
return dp[m - 1][n - 1]| Type | Value |
|---|---|
| Time | O(m*n) |
| Space | O(m*n) |
- Approach: Use a 2D array
dpwheredp[i][j]represents the number of unique paths to reach cell(i, j). The number of paths to(i, j)is the sum of paths from(i-1, j)(above) and(i, j-1)(left). - Dry run (m=3, n=2):
- initialize paths in row 0 and col 0 to 1
- dp = [[1, 1],
[1, ?],
[1, ?]] - i=1, j=1: dp[1][1] = dp[0][1] + dp[1][0] = 1 + 1 = 2
- i=2, j=1: dp[2][1] = dp[1][1] + dp[2][0] = 2 + 1 = 3
- result: dp[2][1] = 3
Minimum Path Sum (LeetCode 64)
Given a
m x ngridfilled with non-negative numbers, find a path from top left to bottom right, which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.
Example 1:

Input: grid = [[1,3,1],[1,5,1],[4,2,1]]
Output: 7
Explanation: Because the path 1 → 3 → 1 → 1 → 1 minimizes the sum.
Example 2:
Input: grid = [[1,2,3],[4,5,6]]
Output: 12
class Solution {
public int minPathSum(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
for (int i = 1; i < m; i++) {
grid[i][0] += grid[i-1][0];
}
for (int j = 1; j < n; j++) {
grid[0][j] += grid[0][j-1];
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
grid[i][j] += Math.min(grid[i-1][j], grid[i][j-1]);
}
}
return grid[m-1][n-1];
}
}class Solution:
def minPathSum(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
for i in range(1, m):
grid[i][0] += grid[i - 1][0]
for j in range(1, n):
grid[0][j] += grid[0][j - 1]
for i in range(1, m):
for j in range(1, n):
grid[i][j] += min(grid[i - 1][j], grid[i][j - 1])
return grid[m - 1][n - 1]| Type | Value |
|---|---|
| Time | O(m*n) |
| Space | O(1) |
- Approach: In-place DP. First accumulate costs along the first column and first row (since there's only one path to reach any cell in row 0 or column 0). Then for each remaining cell, the minimum path sum is the cell's value plus the minimum of the cell above and the cell to the left.
- Dry run (grid = [[1,3,1],[1,5,1],[4,2,1]]):
- First column: grid[1][0]=1+1=2, grid[2][0]=2+4=6
- First row: grid[0][1]=1+3=4, grid[0][2]=4+1=5
- grid[1][1] = 5 + min(4, 2) = 7
- grid[1][2] = 1 + min(5, 7) = 6
- grid[2][1] = 2 + min(7, 6) = 8
- grid[2][2] = 1 + min(6, 8) = 7
- Return 7.
Edit Distance (LeetCode 72)
Given two strings
word1andword2, return the minimum number of operations required to convertword1toword2.You have the following three operations permitted on a word:
- Insert a character
- Delete a character
- Replace a character
Example 1:
Input: word1 = "horse", word2 = "ros"
Output: 3
Explanation:
horse -> rorse (replace 'h' with 'r')
rorse -> rose (remove 'r')
rose -> ros (remove 'e')
Example 2:
Input: word1 = "intention", word2 = "execution"
Output: 5
Explanation:
intention -> inention (remove 't')
inention -> enention (replace 'i' with 'e')
enention -> exention (replace 'n' with 'x')
exention -> exection (replace 'n' with 'c')
exection -> execution (insert 'u')
Constraints:
0 <= word1.length, word2.length <= 500word1andword2consist of lowercase English letters.
class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();
int[][] dp = new int[m + 1][n + 1];
for (int i = 0; i <= m; i++)
dp[i][0] = i;
for (int j = 0; j <= n; j++)
dp[0][j] = j;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (word1.charAt(i - 1) == word2.charAt(j - 1))
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j] = 1 + Math.min(dp[i - 1][j - 1],
Math.min(dp[i - 1][j], dp[i][j - 1]));
}
}
return dp[m][n];
}
}class Solution:
def minDistance(self, word1: str, word2: str) -> int:
m, n = len(word1), len(word2)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
dp[i][0] = i
for j in range(1, n + 1):
dp[0][j] = j
for i in range(1, m + 1):
for j in range(1, n + 1):
if word1[i - 1] == word2[j - 1]:
dp[i][j] = dp[i - 1][j - 1]
else:
dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1
return dp[m][n]| Type | Value |
|---|---|
| Time | O(m*n) |
| Space | O(m*n) |
- Approach: Use a 2D DP array where
dp[i][j]represents the minimum edit distance between the firsticharacters ofword1and the firstjcharacters ofword2. If the characters match,dp[i][j] = dp[i-1][j-1]. Otherwise, consider insertion(dp[i][j-1]), deletion(dp[i-1][j]), and substitution(dp[i-1][j-1])and add 1 to the minimum of these. - Dry run (word1="sea", word2="eat"):
- Initialize
dp: sizes 4x4.dp[i][0] = i,dp[0][j] = j. - i=1 ('s'), j=1 ('e'): no match ->
min(dp[0][0], dp[1][0], dp[0][1]) + 1=min(0, 1, 1) + 1= 1 - i=1 ('s'), j=2 ('a'): no match ->
min(dp[0][1], dp[1][1], dp[0][2]) + 1=min(1, 1, 2) + 1= 2 - i=2 ('e'), j=1 ('e'): match ->
dp[1][0]= 1. - i=3 ('a'), j=2 ('a'): match -> inherits
dp[2][1], which eventually leads to optimal min distance 2.
- Initialize
Climbing Stairs (LeetCode 70)
You are climbing a staircase. It takes
nsteps to reach the top.Each time you can either climb
1or2steps. In how many distinct ways can you climb to the top?
Example 1:
Input: n = 2
Output: 2
Explanation: There are two ways to climb to the top.
- 1 step + 1 step
- 2 steps
Example 2:
Input: n = 3
Output: 3
Explanation: There are three ways to climb to the top.
- 1 step + 1 step + 1 step
- 1 step + 2 steps
- 2 steps + 1 step
class Solution {
public 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;
}
}class Solution:
def climbStairs(self, n: int) -> int:
if n <= 2:
return n
prev2, prev1 = 1, 2
for _ in range(3, n + 1):
curr = prev1 + prev2
prev2 = prev1
prev1 = curr
return prev1| Type | Value |
|---|---|
| Time | O(n) |
| Space | O(1) |
- Approach: Space-optimized DP.
dp[i] = dp[i-1] + dp[i-2]. Track only the last two values. - Dry run (n = 4):
- n=1 -> 1, n=2 -> 2
- i=3: curr = 2 + 1 = 3, prev2=2, prev1=3
- i=4: curr = 3 + 2 = 5, prev2=3, prev1=5
- Return 5
House Robber (LeetCode 198)
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security systems connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given an integer arraynumsrepresenting the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.
Example 1:
Input: nums = [1,2,3,1]
Output: 4
Example 2:
Input: nums = [2,7,9,3,1]
Output: 12
class Solution {
public int rob(int[] nums) {
int prevRob = 0;
int maxRob = 0;
for (int curVal : nums) {
int temp = Math.max(maxRob, prevRob + curVal);
prevRob = maxRob;
maxRob = temp;
}
return maxRob;
}
}class Solution:
def rob(self, nums: List[int]) -> int:
prev_rob = max_rob = 0
for cur_val in nums:
temp = max(max_rob, prev_rob + cur_val)
prev_rob = max_rob
max_rob = temp
return max_rob| Type | Value |
|---|---|
| Time | O(n) |
| Space | O(1) |
- Approach: Dynamic Programming. For each house, we decide to either rob it (adding its value to the maximum amount robbed prior to the previous house) or not rob it (keeping the maximum amount robbed up to the previous house).
- Dry run (nums=[1,2,3,1]):
- 1 -> temp=max(0, 0+1)=1, prev=0, max=1
- 2 -> temp=max(1, 0+2)=2, prev=1, max=2
- 3 -> temp=max(2, 1+3)=4, prev=2, max=4
- 1 -> temp=max(4, 2+1)=4, prev=4, max=4
- Result: 4
House Robber II (LeetCode 213)
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have a security system connected, and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given an integer arraynumsrepresenting the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.
Example 1:
Input: nums = [2,3,2]
Output: 3
Example 2:
Input: nums = [1,2,3,1]
Output: 4
Example 3:
Input: nums = [1,2,3]
Output: 3
class Solution {
public int rob(int[] nums) {
if (nums.length == 1) return nums[0];
return Math.max(robber(nums, 0, nums.length - 2), robber(nums, 1, nums.length - 1));
}
public int robber(int n[], int s, int e) {
int prev_rob = 0;
int max_rob = 0;
int temp = 0;
for (int i = s; i <= e; i++){
temp = Math.max(max_rob, prev_rob + n[i]);
prev_rob = max_rob;
max_rob = temp;
}
return max_rob;
}
}class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) == 1:
return nums[0]
def robber(s, e):
prev_rob = max_rob = 0
for i in range(s, e + 1):
temp = max(max_rob, prev_rob + nums[i])
prev_rob = max_rob
max_rob = temp
return max_rob
return max(robber(0, len(nums) - 2), robber(1, len(nums) - 1))| Type | Value |
|---|---|
| Time | O(n) |
| Space | O(1) |
- Approach: Since the houses are in a circle, we can't rob both the first and the last house. Thus, we solve the basic House Robber problem twice: once from house 0 to n-2, and once from house 1 to n-1. We return the maximum of these two results.
- Dry run (nums=[2,3,2]):
- robber(0, 1) -> input [2,3] -> max=3
- robber(1, 2) -> input [3,2] -> max=3
- max(3, 3) = 3
Decode Ways (LeetCode 91)
91. Decode Ways
You have intercepted a secret message encoded as a string of numbers. The message is decoded via the following mapping:
"1" -> 'A' "2" -> 'B' ... "25" -> 'Y' "26" -> 'Z'
However, while decoding the message, you realize that there are many different ways you can decode the message because some codes are contained in other codes ("2" and "5" vs "25").
For example, "11106" can be decoded into:
"AAJF"with the grouping(1, 1, 10, 6)"KJF"with the grouping(11, 10, 6)- The grouping
(1, 11, 06)is invalid because"06"is not a valid code (only"6"is valid).
Note: there may be strings that are impossible to decode.
Given a string s containing only digits, return the number of ways to decode it. If the entire string cannot be decoded in any valid way, return 0.
The test cases are generated so that the answer fits in a 32-bit integer.
Example 1:
Input: s = "12"
Output: 2
Explanation:
"12" could be decoded as "AB" (1 2) or "L" (12).
Example 2:
Input: s = "226"
Output: 3
Explanation:
"226" could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).
Example 3:
Input: s = "06"
Output: 0
Explanation:
"06" cannot be mapped to "F" because of the leading zero ("6" is different from "06"). In this case, the string is not a valid encoding, so return 0.
class Solution {
public int numDecodings(String s) {
if (s == null || s.length() == 0 || s.charAt(0) == '0') return 0;
int n = s.length();
int twoBack = 1;
int oneBack = 1;
for (int i = 2; i <= n; i++) {
int current = 0;
int oneDigit = s.charAt(i - 1) - '0';
if (oneDigit != 0) {
current += oneBack;
}
int twoDigit = (s.charAt(i - 2) - '0') * 10 + oneDigit;
if (twoDigit >= 10 && twoDigit <= 26) {
current += twoBack;
}
twoBack = oneBack;
oneBack = current;
}
return oneBack;
}
}Longest Common Subsequence (LeetCode 1143)
1143. Longest Common Subsequence
Given two strings
text1andtext2, return the length of their longest common subsequence. If there is no common subsequence, return0.A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters.
Example 1:
Input: text1 = "abcde", text2 = "ace"
Output: 3
Explanation: The longest common subsequence is "ace" and its length is 3.
Example 2:
Input: text1 = "abc", text2 = "abc"
Output: 3
Explanation: The longest common subsequence is "abc" and its length is 3.
Example 3:
Input: text1 = "abc", text2 = "def"
Output: 0
Explanation: There is no such common subsequence, so the result is 0.
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int m = text1.length(), n = text2.length();
int[][] dp = new int[m + 1][n + 1];
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
dp[i][j] = 1 + dp[i - 1][j - 1];
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[m][n];
}
}class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
m, n = len(text1), len(text2)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if text1[i - 1] == text2[j - 1]:
dp[i][j] = 1 + dp[i - 1][j - 1]
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
return dp[m][n]| Type | Value |
|---|---|
| Time | O(m*n) |
| Space | O(m*n) |
- Approach: 2D Dynamic Programming. If characters match
text1[i-1] == text2[j-1],dp[i][j] = 1 + dp[i-1][j-1]. Otherwisedp[i][j] = max(dp[i-1][j], dp[i][j-1]). - Dry run (text1 = "abcde", text2 = "ace"):
- i=1 ('a'), j=1 ('a'): match -> dp[1][1] = 1 + dp[0][0] = 1
- i=2 ('b'), j=1 ('a'): no match -> max(dp[1][1], dp[2][0]) = 1
- i=3 ('c'), j=2 ('c'): match -> dp[3][2] = 1 + dp[2][1] = 2
- i=5 ('e'), j=3 ('e'): match -> dp[5][3] = 1 + dp[4][2] = 3
- Returns 3
Longest Palindromic Subsequence (LeetCode 516)
516. Longest Palindromic Subsequence
Given a string
s, find the longest palindromic subsequence's length ins.A subsequence is a sequence that can be derived from another sequence by deleting some or no elements without changing the order of the remaining elements.
Example 1:
Input: s = "bbbab"
Output: 4
Explanation: One possible longest palindromic subsequence is "bbbb".
Example 2:
Input: s = "cbbd"
Output: 2
Explanation: One possible longest palindromic subsequence is "bb".
class Solution {
public int longestPalindromeSubseq(String s) {
int n = s.length();
int[][] dp = new int[n][n];
for (int i = n - 1; i >= 0; i--) {
dp[i][i] = 1;
for (int j = i + 1; j < n; j++) {
if (s.charAt(i) == s.charAt(j)) {
dp[i][j] = 2 + dp[i + 1][j - 1];
} else {
dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
}
}
}
return dp[0][n - 1];
}
}class Solution:
def longestPalindromeSubseq(self, s: str) -> int:
n = len(s)
dp = [[0] * n for _ in range(n)]
for i in range(n - 1, -1, -1):
dp[i][i] = 1
for j in range(i + 1, n):
if s[i] == s[j]:
dp[i][j] = 2 + dp[i + 1][j - 1]
else:
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])
return dp[0][n - 1]| Type | Value |
|---|---|
| Time | O(n²) |
| Space | O(n²) |
- Approach: Use a 2D DP table where
dp[i][j]represents the length of the longest palindromic subsequence ins[i..j]. Ifs[i] == s[j], extend by 2 fromdp[i+1][j-1]. Otherwise, take the max ofdp[i+1][j]anddp[i][j-1]. Fill the table from bottom-right to top-left. - Dry run (s = "bbbab"):
- All single chars: dp[i][i] = 1
- i=3, j=4: 'a' != 'b' → max(dp[4][4], dp[3][3]) = 1
- i=2, j=3: 'b' != 'a' → 1, j=4: 'b' == 'b' → 2 + dp[3][3] = 3
- Continuing... dp[0][4] = 4
class Solution {
public String longestPalindromeSubseq(String s) {
int n = s.length();
int[][] dp = new int[n][n];
for(int i = n - 1; i >= 0; i--){
dp[i][i] = 1;
for(int j = i + 1; j < n; j++){
if(s.charAt(i) == s.charAt(j))
dp[i][j] = 2 + (i + 1 <= j - 1 ? dp[i + 1][j - 1] : 0);
else
dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
}
}
char[] ans = new char[dp[0][n - 1]];
int i = 0, j = n - 1;
int left = 0, right = ans.length - 1;
while(i <= j){
if(i == j){
ans[left] = s.charAt(i);
break;
}
if(s.charAt(i) == s.charAt(j)){
ans[left++] = s.charAt(i);
ans[right--] = s.charAt(j);
i++;
j--;
}
else if(dp[i + 1][j] >= dp[i][j - 1]){
i++;
}
else{
j--;
}
}
return new String(ans);
}
}Word Break (LeetCode 139)
Given a string
sand a dictionary of stringswordDict, returntrueifscan be segmented into a space-separated sequence of one or more dictionary words.
Example 1:
Input: s = "leetcode", wordDict = ["leet","code"]
Output: true
Explanation: "leetcode" can be segmented as "leet code".
Example 2:
Input: s = "catsandog", wordDict = ["cats","dog","sand","and","cat"]
Output: false
import java.util.*;
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
Set<String> set = new HashSet<>(wordDict);
boolean[] dp = new boolean[s.length() + 1];
dp[0] = true;
for (int i = 1; i <= s.length(); i++) {
for (int j = 0; j < i; j++) {
if (dp[j] && set.contains(s.substring(j, i))) {
dp[i] = true;
break;
}
}
}
return dp[s.length()];
}
}class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
word_set = set(wordDict)
dp = [False] * (len(s) + 1)
dp[0] = True
for i in range(1, len(s) + 1):
for j in range(i):
if dp[j] and s[j:i] in word_set:
dp[i] = True
break
return dp[len(s)]| Type | Value |
|---|---|
| Time | O(n²) |
| Space | O(n) |
- Approach: Use DP.
dp[i]is true ifs[0..i-1]can be segmented. For each positioni, check all substringss[j..i]— ifdp[j]is true and substring is in dict, setdp[i] = true. - Dry run (s = "leetcode", wordDict = ["leet","code"]):
- dp[0]=true
- i=4: j=0, dp[0]=true, s[0..4]="leet" in dict → dp[4]=true
- i=8: j=4, dp[4]=true, s[4..8]="code" in dict → dp[8]=true
- Return dp[8] = true
Coin Change Ways (LeetCode 518)
Given an integer array
coinsrepresenting coins of different denominations and an integeramountrepresenting a total amount of money, return the number of combinations that make up that amount.
Example:
Input: coins = [1, 2, 5], amount = 5
Output: 4
Explanation: There are 4 ways to make up amount 5: [5], [2,2,1], [2,1,1,1], [1,1,1,1,1].
public class CoinChangeWays {
public static int countWays(int[] coins, int amount) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount];
}
}
class CoinChangeWays:
def countWays(self, coins: List[int], amount: int) -> int:
dp = [0] * (amount + 1)
dp[0] = 1
for coin in coins:
for i in range(coin, amount + 1):
dp[i] += dp[i - coin]
return dp[amount]| Type | Value |
|---|---|
| Time | O(n * amount) |
| Space | O(amount) |
- Approach: Use a 1D DP array where
dp[i]represents the number of ways to make amounti. For each coin, iterate through all amounts fromcointoamountand adddp[i - coin]todp[i]. - Dry run (coins={1,2,5}, amount=5):
- start: [1,0,0,0,0,0]
- coin=1 → [1,1,1,1,1,1]
- coin=2 → [1,1,2,2,3,3]
- coin=5 → [1,1,2,2,3,4] → ways=4