Given a m x n grid filled with non-negative numbers, find a path from top-left to bottom-right, which minimizes the sum of all numbers along its path.
You can only move either down or right at any point in time.
π¬ Examples
Example 1
1 2 3
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
1 2
Input: grid = [[1,2,3],[4,5,6]] Output: 12
π‘ Intuition
This is a classic dynamic programming problem on a grid. At each cell (i, j), the minimum path sum equals the cell value plus the smaller of the top or left neighbor:
A robot is located at the top-left corner of an m x n grid (marked start in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked finish).
How many possible unique paths are there?
π¬ Examples
Example 1
1 2
Input: m = 3, n = 7 Output: 28
Example 2
1 2 3 4 5 6
Input: m = 3, n = 2 Output: 3 Explanation: Right -> Down -> Down Down -> Down -> Right Down -> Right -> Down
π‘ Intuition
At each cell (i, j), the number of unique paths to reach it is the sum of paths from the top (i-1, j) and from the left (i, j-1). This gives a dynamic programming relation.
Alternatively, this problem has a combinatorial solution using binomial coefficients: choosing (m-1) downs from (m+n-2) total moves.
π’ Java Code (Dynamic Programming)
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution { publicintuniquePaths(int m, int n) { int[][] dp = newint[m][n]; for (inti=0; i < m; i++) dp[i][0] = 1; for (intj=0; j < n; j++) dp[0][j] = 1; for (inti=1; i < m; i++) { for (intj=1; j < n; j++) { dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; } } return dp[m - 1][n - 1]; } }
π’ Java Code (Combinatorics)
1 2 3 4 5 6 7 8 9
classSolution { publicintuniquePaths(int m, int n) { longres=1; for (inti=1; i <= m - 1; i++) { res = res * (n - 1 + i) / i; } return (int) res; } }
β± Complexity Analysis
DP approach:
Time: O(m Γ n)
Space: O(m Γ n) (can be optimized to O(n))
Combinatorics:
Time: O(m)
Space: O(1)
βοΈ Summary
Grid path counting reduces to a classic DP problem.
Alternatively, solve with binomial coefficient.
Use combinatorics for very large grids to avoid DP overhead.
Related problems: lc-63 (Unique Paths II), lc-64 (Minimum Path Sum).
Given a non-empty array nums containing only positive integers, determine if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.
Return true if such a partition exists, otherwise return false.
π¬ Examples
Example 1
1 2 3
Input: nums = [1,5,11,5] Output: true Explanation: The array can be partitioned as [1,5,5] and [11].
Example 2
1 2 3
Input: nums = [1,2,3,5] Output: false Explanation: The array cannot be partitioned into equal sum subsets.
π‘ Intuition
If the total sum is odd, itβs impossible to split into two equal subsets. Otherwise, the problem reduces to: can we find a subset with sum equal to target = totalSum / 2?
This is the classic subset sum problem and can be solved using dynamic programming (0/1 knapsack style) or using a bitset optimization. We aim for a boolean DP where dp[s] indicates whether a subset with sum s is achievable.
π’ Java Code (1D DP - optimized 0/1 knapsack)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution { publicbooleancanPartition(int[] nums) { intsum=0; for (int num : nums) sum += num; if ((sum & 1) == 1) returnfalse; inttarget= sum / 2; boolean[] dp = newboolean[target + 1]; dp[0] = true; for (int num : nums) { for (ints= target; s >= num; s--) { dp[s] = dp[s] || dp[s - num]; } if (dp[target]) returntrue; // early exit } return dp[target]; } }
classSolution { publicbooleancanPartition(int[] nums) { intsum=0; for (int n : nums) sum += n; if ((sum & 1) == 1) returnfalse; inttarget= sum / 2; BitSetbits=newBitSet(target + 1); bits.set(0); for (int n : nums) { BitSetshifted= bits.get(0, target + 1 - n); // Implement left-shift by iterating backwards and setting bits appropriately. for (inti= target - n; i >= 0; i--) { if (bits.get(i)) bits.set(i + n); } if (bits.get(target)) returntrue; } return bits.get(target); } }
Note: Javaβs BitSet doesnβt provide a direct shiftLeft method β you can implement shifting by iterating or using a long-based trick for fixed-size bitsets. The 1D boolean DP is simpler and sufficiently fast for typical constraints.
β± Complexity Analysis
Time: O(n Γ target) β where n is the number of elements.
Space: O(target) β 1D DP array.
βοΈ Summary
Check total sum parity first.
Reduce to subset-sum with target = totalSum / 2.
Use 1D DP (iterate backwards) to avoid reusing elements.
Early exit if dp[target] becomes true during iteration.
Related problems: lc-494 (Target Sum), lc-216 (Combination Sum III), lc-698 (Partition to K Equal Sum Subsets).
Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product, and return the product.
π¬ Examples
Example 1
1 2 3
Input: nums = [2,3,-2,4] Output: 6 Explanation: [2,3] has the largest product 6.
Example 2
1 2 3
Input: nums = [-2,0,-1] Output: 0 Explanation: The result cannot be 2 because [-2,-1] is not a contiguous subarray in this case.
π‘ Intuition
Because the product of numbers is affected by the sign, a negative number can turn a small (negative) product into a large positive one, and vice versa. Therefore, at each position we need to track both the maximum and minimum product ending at that position.
Let maxF[i] be the maximum product ending at i, and minF[i] the minimum product ending at i. Then:
Given an integer array nums, return the length of the longest strictly increasing subsequence.
A subsequence is a sequence that can be derived from an array by deleting some or no elements without changing the order of the remaining elements.
π¬ Examples
Example 1
1 2 3
Input: nums = [10,9,2,5,3,7,101,18] Output: 4 Explanation: The longest increasing subsequence is [2,3,7,101].
Example 2
1 2
Input: nums = [0,1,0,3,2,3] Output: 4
Example 3
1 2
Input: nums = [7,7,7,7,7,7,7] Output: 1
π‘ Approaches
1) Dynamic Programming (O(nΒ²))
Let dp[i] be the length of the longest increasing subsequence ending at index i. Transition: for each j < i, if nums[j] < nums[i] then dp[i] = max(dp[i], dp[j] + 1). Answer is max(dp[i]) over all i.
Maintain an array tails[len] where tails[k] is the smallest possible tail value of an increasing subsequence with length k+1. For each number x in nums, binary search the first index in tails with value β₯ x and replace it with x. If x is greater than all tails, append it. The length of tails is the LIS length.
This method gives O(n log n) time and O(n) space and is the recommended optimal solution for large inputs.
π’ Java Code β DP (O(nΒ²))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
classSolution { publicintlengthOfLIS(int[] nums) { if (nums == null || nums.length == 0) return0; intn= nums.length; int[] dp = newint[n]; Arrays.fill(dp, 1); intmax=1; for (inti=0; i < n; i++) { for (intj=0; j < i; j++) { if (nums[j] < nums[i]) { dp[i] = Math.max(dp[i], dp[j] + 1); } } max = Math.max(max, dp[i]); } return max; } }
π’ Java Code β Patience Sorting (O(n log n))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
import java.util.*;
classSolution { publicintlengthOfLIS(int[] nums) { if (nums == null || nums.length == 0) return0; List<Integer> tails = newArrayList<>(); for (int x : nums) { inti= Collections.binarySearch(tails, x); if (i < 0) i = -(i + 1); if (i == tails.size()) tails.add(x); else tails.set(i, x); } return tails.size(); } }
Note: Collections.binarySearch returns -(insertionPoint) - 1 when the key is not found; the code above converts it into the insertion point.
β± Complexity Analysis
DP: Time O(nΒ²), Space O(n).
Patience Sorting: Time O(n log n), Space O(n).
βοΈ Summary
Use DP for clarity or small n.
For large inputs, use the O(n log n) approach with tails + binary search (often called patience sorting).
The tails array stores the smallest possible tail for an increasing subsequence of each length; its size equals the LIS length.
Given a string s and a dictionary of strings wordDict, return true if s can be segmented into a space-separated sequence of one or more dictionary words.
You may assume the dictionary does not contain duplicate words.
Input: s = "catsandog", wordDict = ["cats","dog","sand","and","cat"] Output: false
π‘ Intuition
We want to determine whether s can be split into valid words from wordDict. Two common approaches:
Dynamic Programming (DP): Let dp[i] be true if s[0..i) can be segmented. For each i, check all possible previous cuts j < i and if dp[j] is true and s[j..i) is in wordDict, set dp[i] = true.
BFS / Trie: Treat positions as nodes and edges when substring is a word; run BFS from position 0 to n to avoid redundant work.
DP is simple and efficient when implemented with a hash set for dictionary lookups and pruning via max word length.
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. The only constraint is: adjacent houses cannot be robbed on the same night.
Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.
π¬ Examples
Example 1
1 2 3
Input: nums = [1,2,3,1] Output: 4 Explanation: Rob house 1 (1) + house 3 (3).
Example 2
1 2 3
Input: nums = [2,7,9,3,1] Output: 12 Explanation: Rob house 1 (2) + house 3 (9) + house 5 (1).
π‘ Intuition
This is a dynamic programming problem. At each house i, you decide to either: