easy questions

This commit is contained in:
2025-04-28 21:47:07 +01:00
parent 2e9c38f71b
commit c4856d9948
2 changed files with 191 additions and 0 deletions

View 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.

View 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.