SvenStack

Tech Share

🧩 Problem Description

Given an integer numRows, return the first numRows of Pascal’s triangle.

In Pascal’s triangle, each number is the sum of the two numbers directly above it as shown:

1
2
3
4
5
    1
1 1
1 2 1
1 3 3 1
1 4 6 4 1

πŸ’¬ Examples

Example 1

1
2
Input: numRows = 5
Output: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]

Example 2

1
2
Input: numRows = 1
Output: [[1]]

πŸ’‘ Intuition

Each row starts and ends with 1. For intermediate elements, the value equals the sum of the two elements above it from the previous row. We can build rows iteratively from top to bottom.


πŸ”’ Java Code (Iterative)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.*;

class Solution {
public List<List<Integer>> generate(int numRows) {
List<List<Integer>> res = new ArrayList<>();
for (int i = 0; i < numRows; i++) {
List<Integer> row = new ArrayList<>();
for (int j = 0; j <= i; j++) {
if (j == 0 || j == i) row.add(1);
else {
List<Integer> prev = res.get(i - 1);
row.add(prev.get(j - 1) + prev.get(j));
}
}
res.add(row);
}
return res;
}
}

⏱ Complexity Analysis

  • Time: O(numRows^2) β€” we fill each entry of the triangle once.
  • Space: O(numRows^2) β€” output size.

✍️ Summary

  • Build each row using the previous row’s values.
  • Simple, iterative approach works efficiently for the problem constraints.

Related problems

  • lc-119 β€” Pascal’s Triangle II (specific row)
  • lc-118 variations involving combinatorics

🧩 Problem Description

You are climbing a staircase. It takes n steps to reach the top.

Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?


πŸ’¬ Examples

Example 1

1
2
3
Input: n = 2
Output: 2
Explanation: 1 step + 1 step OR 2 steps.

Example 2

1
2
3
Input: n = 3
Output: 3
Explanation: 1+1+1, 1+2, 2+1.

πŸ’‘ Intuition

This is a dynamic programming problem, equivalent to computing the Fibonacci sequence.

  • Let dp[i] be the number of ways to climb i steps.
  • Transition: dp[i] = dp[i-1] + dp[i-2].
  • Base cases: dp[1] = 1, dp[2] = 2.

We can optimize space to O(1) by just keeping the last two states.


πŸ”’ Java Code (DP Optimized)

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public int climbStairs(int n) {
if (n <= 2) return n;
int a = 1, b = 2;
for (int i = 3; i <= n; i++) {
int c = a + b;
a = b;
b = c;
}
return b;
}
}

⏱ Complexity Analysis

  • Time: O(n) β€” linear iteration.
  • Space: O(1) β€” only two variables stored.

✍️ Summary

  • Equivalent to computing Fibonacci numbers.
  • Use DP or iterative approach for efficiency.
  • Space optimized to O(1).

Related problems

  • lc-746 β€” Min Cost Climbing Stairs
  • lc-509 β€” Fibonacci Number

🧩 Problem Description

A string S of lowercase letters is given. We want to partition this string into as many parts as possible so that each letter appears in at most one part, and return a list of integers representing the size of these parts.


πŸ’¬ Example

1
2
3
4
5
Input: S = "ababcbacadefegdehijhklij"
Output: [9,7,8]
Explanation:
The partition is "ababcbaca", "defegde", "hijhklij".
Each letter appears in at most one part.

πŸ’‘ Intuition

We want to cut the string into maximum number of parts such that no character appears in more than one part.
Key idea: for each character, precompute its last occurrence index. Then scan the string and maintain a running end which is the farthest last occurrence of characters seen so far. When the current index reaches end, we can close a partition (from previous cut to end) and start a new one.

This is a greedy strategy: always close a partition as soon as every character inside it cannot appear later.


πŸ”’ Java Code (Greedy)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.*;

class Solution {
public List<Integer> partitionLabels(String S) {
int n = S.length();
int[] last = new int[26];
for (int i = 0; i < n; i++) {
last[S.charAt(i) - 'a'] = i;
}
List<Integer> res = new ArrayList<>();
int start = 0, end = 0;
for (int i = 0; i < n; i++) {
end = Math.max(end, last[S.charAt(i) - 'a']);
if (i == end) {
res.add(end - start + 1);
start = i + 1;
}
}
return res;
}
}

⏱ Complexity Analysis

  • Time: O(n) β€” one pass to compute last positions and one pass to partition.
  • Space: O(1) (excluding output) β€” fixed-size array of 26 for lowercase letters.

✍️ Summary

  • Precompute each character’s last occurrence.
  • Scan and extend the current partition’s end to cover all last occurrences of letters seen.
  • When current index equals the partition end, emit partition size and start a new one.

Related problems

  • lc-763 variations with different alphabets or constraints

🧩 Problem Description

You are given a 0-indexed array of integers nums of length n. You are initially positioned at the first index.
Each element nums[i] represents the maximum length of a forward jump from index i.

Return the minimum number of jumps to reach the last index. The test cases are generated such that you can always reach the last index.


πŸ’¬ Examples

Example 1

1
2
3
4
Input: nums = [2,3,1,1,4]
Output: 2
Explanation: The minimum number of jumps is 2.
Jump 1 step from index 0 to 1, then 3 steps to the last index.

Example 2

1
2
Input: nums = [2,3,0,1,4]
Output: 2

πŸ’‘ Intuition

This problem can be solved using a greedy approach.

  • We want to minimize the number of jumps.
  • Track two variables while scanning:
    • currentEnd: the farthest point reachable with the current number of jumps.
    • farthest: the farthest point reachable by the next jump.
  • Each time we reach currentEnd, we must make another jump, and update currentEnd = farthest.

This guarantees minimum jumps since we always extend as far as possible at each step.


πŸ”’ Java Code (Greedy)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public int jump(int[] nums) {
int jumps = 0;
int farthest = 0;
int currentEnd = 0;
for (int i = 0; i < nums.length - 1; i++) {
farthest = Math.max(farthest, i + nums[i]);
if (i == currentEnd) {
jumps++;
currentEnd = farthest;
}
}
return jumps;
}
}

⏱ Complexity Analysis

  • Time: O(n) β€” linear scan.
  • Space: O(1).

✍️ Summary

  • Use a greedy strategy to expand the farthest reach at each step.
  • Each time you exhaust the current range, increment jumps and move to the next range.
  • Efficient O(n) solution.

Related problems

  • lc-55 β€” Jump Game
  • lc-1306 β€” Jump Game III
  • lc-1345 β€” Jump Game IV

🧩 Problem Description

You are given an integer array nums. You are initially positioned at the first index, and each element in the array represents your maximum jump length at that position.

Return true if you can reach the last index, or false otherwise.


πŸ’¬ Examples

Example 1

1
2
3
Input: nums = [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.

Example 2

1
2
3
Input: nums = [3,2,1,0,4]
Output: false
Explanation: You will always arrive at index 3 with a maximum jump length 0, so cannot move forward.

πŸ’‘ Intuition

We need to check whether it’s possible to reach the last index:

  • Keep track of the farthest position reachable while traversing the array.
  • If at any index i, i > farthest, then we cannot reach this index β†’ return false.
  • Otherwise, update farthest = max(farthest, i + nums[i]).
  • If the farthest index is at least the last index, return true.

This is a classic greedy approach.


πŸ”’ Java Code (Greedy)

1
2
3
4
5
6
7
8
9
10
class Solution {
public boolean canJump(int[] nums) {
int farthest = 0;
for (int i = 0; i < nums.length; i++) {
if (i > farthest) return false;
farthest = Math.max(farthest, i + nums[i]);
}
return true;
}
}

⏱ Complexity Analysis

  • Time: O(n) β€” single pass.
  • Space: O(1).

✍️ Summary

  • Maintain the farthest index reachable while iterating.
  • If you ever get stuck (i > farthest), return false.
  • Greedy solution ensures linear time complexity.

Related problems

  • lc-45 β€” Jump Game II
  • lc-1306 β€” Jump Game III
  • lc-1345 β€” Jump Game IV

🧩 Problem Description

You are given an array prices where prices[i] is the price of a given stock on the i-th day.
You want to maximize your profit by choosing a single day to buy one stock and choosing a different day in the future to sell that stock.
Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return 0.


πŸ’¬ Examples

Example 1

1
2
3
Input: prices = [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6 - 1 = 5.

Example 2

1
2
3
Input: prices = [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done and the max profit = 0.

πŸ’‘ Intuition

We want the largest difference prices[j] - prices[i] with j > i.
A simple linear scan can track the minimum price so far and compute the potential profit at each day by subtracting the current min from the current price. Keep the maximum profit encountered. This is a greedy O(n) solution.


πŸ”’ Java Code (One-pass Greedy)

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public int maxProfit(int[] prices) {
if (prices == null || prices.length == 0) return 0;
int minPrice = Integer.MAX_VALUE;
int maxProfit = 0;
for (int price : prices) {
if (price < minPrice) minPrice = price;
else if (price - minPrice > maxProfit) maxProfit = price - minPrice;
}
return maxProfit;
}
}

πŸ”„ Alternative (Kadane-like)

You can view the problem as finding the maximum subarray sum of daily differences diff[i] = prices[i] - prices[i-1]. Apply Kadane’s algorithm to diff to get the same O(n) result.


⏱ Complexity Analysis

  • Time: O(n) β€” single pass through prices.
  • Space: O(1) β€” constant extra memory.

✍️ Summary

  • Track the minimum buying price so far and update the maximum profit at each step.
  • Very efficient greedy solution: O(n) time, O(1) space.

Related problems

  • lc-122 β€” Best Time to Buy and Sell Stock II
  • lc-123 β€” Best Time to Buy and Sell Stock III
  • lc-188 β€” Best Time to Buy and Sell Stock IV

🧩 Problem Description

The MedianFinder class:

  • MedianFinder() initializes the object.
  • void addNum(int num) adds the integer num to the data structure.
  • double findMedian() returns the median of all elements so far.

πŸ’¬ Examples

Example 1

1
2
3
4
5
6
Input:
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]

Output:
[null, null, null, 1.5, null, 2.0]

πŸ’‘ Intuition

To efficiently find the median:

  • Use two heaps:

    • A max-heap (left) to store the smaller half of numbers.
    • A min-heap (right) to store the larger half of numbers.
  • Balancing rule:

    • Either both heaps have equal size, or left has one more element.
    • Median = root of max-heap (if odd) or average of roots (if even).

πŸ”’ Java Code (Two Heaps)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.*;

class MedianFinder {
private PriorityQueue<Integer> left; // max-heap
private PriorityQueue<Integer> right; // min-heap

public MedianFinder() {
left = new PriorityQueue<>(Collections.reverseOrder());
right = new PriorityQueue<>();
}

public void addNum(int num) {
left.offer(num);
right.offer(left.poll());

if (right.size() > left.size()) {
left.offer(right.poll());
}
}

public double findMedian() {
if (left.size() > right.size()) {
return left.peek();
} else {
return (left.peek() + right.peek()) / 2.0;
}
}
}

⏱ Complexity Analysis

  • Time (per operation): O(log n)
  • Space: O(n)

✍️ Summary

  • Two Heaps maintain balance between left and right halves.
  • Ensures O(log n) per insertion and O(1) median query.

Related problems

  • lc-480 β€” Sliding Window Median
  • lc-703 β€” Kth Largest Element in a Stream
  • lc-220 β€” Contains Duplicate III

🧩 Problem Description

Given an integer array nums and an integer k, return the k most frequent elements.
You may return the answer in any order.


πŸ’¬ Examples

Example 1

1
2
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]

Example 2

1
2
Input: nums = [1], k = 1
Output: [1]

πŸ’‘ Intuition

Two common solutions:

  1. Heap (PriorityQueue):

    • Count frequencies using HashMap.
    • Maintain a min-heap of size k.
    • Time: O(n log k).
  2. Bucket Sort:

    • Frequencies range from 1 to n.
    • Place numbers into buckets indexed by frequency.
    • Traverse from high frequency to low until k elements are collected.
    • Time: O(n).

πŸ”’ Java Code (Heap)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.*;

class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> freqMap = new HashMap<>();
for (int num : nums) {
freqMap.put(num, freqMap.getOrDefault(num, 0) + 1);
}

PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> a[1] - b[1]);

for (Map.Entry<Integer, Integer> entry : freqMap.entrySet()) {
heap.offer(new int[]{entry.getKey(), entry.getValue()});
if (heap.size() > k) {
heap.poll();
}
}

int[] result = new int[k];
for (int i = k - 1; i >= 0; i--) {
result[i] = heap.poll()[0];
}
return result;
}
}

πŸ”’ Java Code (Bucket Sort)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.*;

class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer, Integer> freqMap = new HashMap<>();
for (int num : nums) {
freqMap.put(num, freqMap.getOrDefault(num, 0) + 1);
}

List<Integer>[] buckets = new List[nums.length + 1];
for (int key : freqMap.keySet()) {
int freq = freqMap.get(key);
if (buckets[freq] == null) {
buckets[freq] = new ArrayList<>();
}
buckets[freq].add(key);
}

List<Integer> result = new ArrayList<>();
for (int i = buckets.length - 1; i >= 0 && result.size() < k; i--) {
if (buckets[i] != null) {
result.addAll(buckets[i]);
}
}

return result.stream().mapToInt(x -> x).toArray();
}
}

⏱ Complexity Analysis

Heap Solution

  • Time: O(n log k)
  • Space: O(n)

Bucket Sort Solution

  • Time: O(n)
  • Space: O(n)

✍️ Summary

  • Use heap for balanced performance.
  • Use bucket sort for O(n) solution.

Related problems

  • lc-215 β€” Kth Largest Element in an Array
  • lc-451 β€” Sort Characters By Frequency
  • lc-973 β€” K Closest Points to Origin

🧩 Problem Description

Given an integer array nums and an integer k, return the k-th largest element in the array.
Note: It is the k-th largest element in the sorted order, not the k-th distinct element.


πŸ’¬ Examples

Example 1

1
2
Input: nums = [3,2,1,5,6,4], k = 2
Output: 5

Example 2

1
2
Input: nums = [3,2,3,1,2,4,5,5,6], k = 4
Output: 4

πŸ’‘ Intuition

There are two common approaches:

  1. Heap (Min-Heap of size k):

    • Maintain a heap of the largest k elements.
    • The root of the heap is the answer.
    • Time: O(n log k).
  2. Quickselect (Hoare’s selection algorithm):

    • Similar to quicksort partitioning.
    • Average time: O(n), worst-case O(nΒ²).
    • More efficient in practice.

πŸ”’ Java Code (Heap)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.*;

class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
for (int num : nums) {
minHeap.offer(num);
if (minHeap.size() > k) {
minHeap.poll();
}
}
return minHeap.peek();
}
}

πŸ”’ Java Code (Quickselect)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public int findKthLargest(int[] nums, int k) {
int n = nums.length;
return quickSelect(nums, 0, n - 1, n - k);
}

private int quickSelect(int[] nums, int left, int right, int k) {
int pivot = nums[right];
int p = left;
for (int i = left; i < right; i++) {
if (nums[i] <= pivot) {
swap(nums, i, p);
p++;
}
}
swap(nums, p, right);

if (p == k) return nums[p];
else if (p < k) return quickSelect(nums, p + 1, right, k);
else return quickSelect(nums, left, p - 1, k);
}

private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}

⏱ Complexity Analysis

Heap Solution

  • Time: O(n log k)
  • Space: O(k)

Quickselect Solution

  • Time: O(n) on average, O(nΒ²) worst-case
  • Space: O(1)

✍️ Summary

  • Use min-heap for simplicity.
  • Use quickselect for optimal performance on average.

Related problems

  • lc-347 β€” Top K Frequent Elements
  • lc-973 β€” K Closest Points to Origin
  • lc-703 β€” Kth Largest Element in a Stream

🧩 Problem Description

Given an array of integers heights representing the histogram’s bar height where the width of each bar is 1, return the area of the largest rectangle in the histogram.


πŸ’¬ Examples

Example 1

1
2
3
Input: heights = [2,1,5,6,2,3]
Output: 10
Explanation: The largest rectangle is formed by bars with height 5 and 6, width = 2 β†’ area = 10.

Example 2

1
2
Input: heights = [2,4]
Output: 4

πŸ’‘ Intuition

We want to find the largest rectangle area in a histogram.
A monotonic increasing stack helps track the left and right boundaries for each bar:

  • Traverse the bars.
  • While current height is less than the top of stack, pop from stack and calculate area.
  • Area = poppedHeight * (currentIndex - stackTopAfterPop - 1).
  • Push current index onto the stack.
  • Add sentinel 0 at the end to flush out remaining bars.

πŸ”’ Java Code (Monotonic Stack)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.*;

class Solution {
public int largestRectangleArea(int[] heights) {
int n = heights.length;
Stack<Integer> stack = new Stack<>();
int maxArea = 0;

for (int i = 0; i <= n; i++) {
int h = (i == n ? 0 : heights[i]);
while (!stack.isEmpty() && h < heights[stack.peek()]) {
int height = heights[stack.pop()];
int width = stack.isEmpty() ? i : i - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}

return maxArea;
}
}

⏱ Complexity Analysis

  • Time: O(n) β€” each bar pushed and popped at most once.
  • Space: O(n) β€” stack storage.

✍️ Summary

  • Use monotonic increasing stack to efficiently compute rectangle areas.
  • Each bar defines a rectangle extended until a smaller bar appears.

Related problems

  • lc-85 β€” Maximal Rectangle
  • lc-42 β€” Trapping Rain Water
  • lc-239 β€” Sliding Window Maximum
0%