easy questions
This commit is contained in:
89
backend/data/questions/best-time-to-buy-and-sell-stock.yaml
Normal file
89
backend/data/questions/best-time-to-buy-and-sell-stock.yaml
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
title: Best Time to Buy and Sell Stock
|
||||||
|
slug: best-time-to-buy-and-sell-stock
|
||||||
|
difficulty: easy
|
||||||
|
leetcode_id: 121
|
||||||
|
leetcode_url: https://leetcode.com/problems/best-time-to-buy-and-sell-stock/
|
||||||
|
categories:
|
||||||
|
- arrays
|
||||||
|
- dynamic-programming
|
||||||
|
patterns:
|
||||||
|
- greedy
|
||||||
|
|
||||||
|
description: |
|
||||||
|
You are given an array `prices` where `prices[i]` is the price of a given stock on the ith 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.
|
||||||
|
|
||||||
|
constraints: |
|
||||||
|
- 1 <= prices.length <= 10^5
|
||||||
|
- 0 <= prices[i] <= 10^4
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- 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."
|
||||||
|
- input: "prices = [7,6,4,3,1]"
|
||||||
|
output: "0"
|
||||||
|
explanation: "No profitable transaction possible."
|
||||||
|
|
||||||
|
explanation:
|
||||||
|
approach: |
|
||||||
|
1. Track the minimum price seen so far
|
||||||
|
2. For each day, calculate the profit if we sold today
|
||||||
|
3. Update maximum profit if current profit is higher
|
||||||
|
4. Update minimum price if current price is lower
|
||||||
|
|
||||||
|
intuition: |
|
||||||
|
To maximize profit, we want to buy at the lowest price and sell at the highest price after
|
||||||
|
that. Rather than comparing all pairs (O(n²)), we track the minimum price seen so far.
|
||||||
|
|
||||||
|
For each day, we ask: "If I sold today, what's the maximum profit?" This is simply
|
||||||
|
today's price minus the minimum price we've seen before today.
|
||||||
|
|
||||||
|
common_pitfalls:
|
||||||
|
- title: Selling before buying
|
||||||
|
description: |
|
||||||
|
Ensure you only consider selling on days after the minimum price was observed.
|
||||||
|
Tracking minimum as you iterate handles this automatically.
|
||||||
|
wrong_approach: "Using global min and max without considering order"
|
||||||
|
correct_approach: "Track running minimum, calculate profit from that point"
|
||||||
|
|
||||||
|
- title: Initializing min_price to 0
|
||||||
|
description: |
|
||||||
|
Initialize min_price to the first element or infinity, not 0, since prices are positive
|
||||||
|
and you need to track actual minimum.
|
||||||
|
|
||||||
|
key_takeaways:
|
||||||
|
- Single pass through array is sufficient
|
||||||
|
- Track running minimum for optimal buy point
|
||||||
|
- Greedy approach works when you can only make one transaction
|
||||||
|
- This is a foundation for more complex stock problems
|
||||||
|
|
||||||
|
time_complexity: "O(n)"
|
||||||
|
space_complexity: "O(1)"
|
||||||
|
complexity_explanation: |
|
||||||
|
Time: Single pass through the prices array.
|
||||||
|
Space: Only two variables needed (min_price, max_profit).
|
||||||
|
|
||||||
|
solutions:
|
||||||
|
- approach_name: Single Pass (Optimal)
|
||||||
|
is_optimal: true
|
||||||
|
code: |
|
||||||
|
def max_profit(prices: list[int]) -> int:
|
||||||
|
min_price = float('inf')
|
||||||
|
max_profit = 0
|
||||||
|
|
||||||
|
for price in prices:
|
||||||
|
if price < min_price:
|
||||||
|
min_price = price
|
||||||
|
elif price - min_price > max_profit:
|
||||||
|
max_profit = price - min_price
|
||||||
|
|
||||||
|
return max_profit
|
||||||
|
explanation: |
|
||||||
|
Track minimum price seen so far and maximum profit achievable.
|
||||||
|
Update both as we iterate through prices.
|
||||||
102
backend/data/questions/climbing-stairs.yaml
Normal file
102
backend/data/questions/climbing-stairs.yaml
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
title: Climbing Stairs
|
||||||
|
slug: climbing-stairs
|
||||||
|
difficulty: easy
|
||||||
|
leetcode_id: 70
|
||||||
|
leetcode_url: https://leetcode.com/problems/climbing-stairs/
|
||||||
|
categories:
|
||||||
|
- dynamic-programming
|
||||||
|
- math
|
||||||
|
patterns:
|
||||||
|
- dynamic-programming
|
||||||
|
|
||||||
|
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?
|
||||||
|
|
||||||
|
constraints: |
|
||||||
|
- 1 <= n <= 45
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- input: "n = 2"
|
||||||
|
output: "2"
|
||||||
|
explanation: "Two ways: (1+1) or (2)"
|
||||||
|
- input: "n = 3"
|
||||||
|
output: "3"
|
||||||
|
explanation: "Three ways: (1+1+1), (1+2), (2+1)"
|
||||||
|
|
||||||
|
explanation:
|
||||||
|
approach: |
|
||||||
|
1. Recognize this follows the Fibonacci pattern
|
||||||
|
2. ways(n) = ways(n-1) + ways(n-2)
|
||||||
|
3. From step n-1, we can take 1 step to reach n
|
||||||
|
4. From step n-2, we can take 2 steps to reach n
|
||||||
|
5. Base cases: ways(1) = 1, ways(2) = 2
|
||||||
|
|
||||||
|
intuition: |
|
||||||
|
At any step, you either got there by taking 1 step from the previous position
|
||||||
|
or 2 steps from two positions back. This gives us the recurrence relation.
|
||||||
|
|
||||||
|
This is essentially the Fibonacci sequence! The number of ways to reach step n
|
||||||
|
equals the sum of ways to reach steps n-1 and n-2.
|
||||||
|
|
||||||
|
common_pitfalls:
|
||||||
|
- title: Using recursion without memoization
|
||||||
|
description: |
|
||||||
|
Naive recursion recalculates the same subproblems repeatedly, leading to
|
||||||
|
exponential time complexity. Either use memoization or iterative DP.
|
||||||
|
wrong_approach: "return climb(n-1) + climb(n-2) without caching"
|
||||||
|
correct_approach: "Use bottom-up DP or memoize recursive calls"
|
||||||
|
|
||||||
|
- title: Off-by-one in base cases
|
||||||
|
description: |
|
||||||
|
Carefully define base cases. There's 1 way to stay at ground (step 0),
|
||||||
|
1 way to reach step 1, and 2 ways to reach step 2.
|
||||||
|
|
||||||
|
key_takeaways:
|
||||||
|
- Many counting problems follow Fibonacci-like patterns
|
||||||
|
- Convert recursion to iteration for O(1) space
|
||||||
|
- Bottom-up DP avoids stack overflow for large inputs
|
||||||
|
- Recognize overlapping subproblems as a DP signal
|
||||||
|
|
||||||
|
time_complexity: "O(n)"
|
||||||
|
space_complexity: "O(1)"
|
||||||
|
complexity_explanation: |
|
||||||
|
Time: We compute n states, each in O(1).
|
||||||
|
Space: Only track two previous values (space-optimized DP).
|
||||||
|
|
||||||
|
solutions:
|
||||||
|
- approach_name: Space-Optimized DP (Optimal)
|
||||||
|
is_optimal: true
|
||||||
|
code: |
|
||||||
|
def climb_stairs(n: int) -> int:
|
||||||
|
if n <= 2:
|
||||||
|
return n
|
||||||
|
|
||||||
|
prev1, prev2 = 2, 1
|
||||||
|
for i in range(3, n + 1):
|
||||||
|
current = prev1 + prev2
|
||||||
|
prev2 = prev1
|
||||||
|
prev1 = current
|
||||||
|
|
||||||
|
return prev1
|
||||||
|
explanation: |
|
||||||
|
Track only the two previous values since that's all we need.
|
||||||
|
Equivalent to computing the nth Fibonacci number.
|
||||||
|
|
||||||
|
- approach_name: Recursive with Memoization
|
||||||
|
is_optimal: false
|
||||||
|
code: |
|
||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
def climb_stairs(n: int) -> int:
|
||||||
|
@lru_cache(maxsize=None)
|
||||||
|
def dp(step: int) -> int:
|
||||||
|
if step <= 2:
|
||||||
|
return step
|
||||||
|
return dp(step - 1) + dp(step - 2)
|
||||||
|
|
||||||
|
return dp(n)
|
||||||
|
explanation: |
|
||||||
|
Top-down approach with memoization.
|
||||||
|
Uses O(n) space for the cache and recursion stack.
|
||||||
Reference in New Issue
Block a user