Əsas məzmuna keçin

Climbing Stairs (Pillələrə Qalxma)

Problem Təsviri

Siz n pillədən ibarət pilləkənin aşağısındasınız. Hər dəfə ya 1 pillə, ya da 2 pillə qalxa bilərsiniz. Zirvəyə çatmaq üçün neçə fərqli yol var?

Məsələn:

  • n = 2 üçün: 2 yol var (1+1 və ya 2)
  • n = 3 üçün: 3 yol var (1+1+1, 1+2, 2+1)
  • n = 4 üçün: 5 yol var (1+1+1+1, 1+1+2, 1+2+1, 2+1+1, 2+2)

Pattern: Bu problem əslində Fibonacci ardıcıllığı ilə eynidir!

  • ways(n) = ways(n-1) + ways(n-2)

Müxtəlif Yanaşmalar

1. Sadə Rekursiya (Naive Approach)

Koda bax
public class ClimbingStairsNaive {

public static int climbStairs(int n) {
// Base cases
if (n <= 2) {
return n;
}

// From step n, we could have come from (n-1) or (n-2)
return climbStairs(n - 1) + climbStairs(n - 2);
}

public static void main(String[] args) {
System.out.println("Climbing Stairs (Naive Recursion):");

for (int i = 1; i <= 10; i++) {
System.out.println("n = " + i + ", yollar = " + climbStairs(i));
}

// Performance test
long startTime = System.currentTimeMillis();
int result = climbStairs(35);
long endTime = System.currentTimeMillis();

System.out.println("\nn = 35, yollar = " + result);
System.out.println("Vaxt: " + (endTime - startTime) + " ms");
}
}

Mürəkkəblik:

  • Time Complexity: O(2^n) - Eksponensial
  • Space Complexity: O(n) - Rekursiya stack-i üçün

Problemlər:

  • Böyük n dəyərləri üçün çox yavaş
  • Eyni alt-problemlər dəfələrlə hesablanır

2. Memoization (Top-Down DP)

Koda bax
import java.util.HashMap;
import java.util.Map;

public class ClimbingStairsMemoization {

// Using HashMap for memoization
private static Map<Integer, Integer> memo = new HashMap<>();

public static int climbStairs(int n) {
// Base cases
if (n <= 2) {
return n;
}

// Check if already computed
if (memo.containsKey(n)) {
return memo.get(n);
}

// Compute and store result
int result = climbStairs(n - 1) + climbStairs(n - 2);
memo.put(n, result);

return result;
}

// Alternative implementation with array
public static int climbStairsArray(int n) {
if (n <= 2) return n;

int[] memo = new int[n + 1];
return climbStairsHelper(n, memo);
}

private static int climbStairsHelper(int n, int[] memo) {
if (n <= 2) {
return n;
}

if (memo[n] != 0) {
return memo[n];
}

memo[n] = climbStairsHelper(n - 1, memo) + climbStairsHelper(n - 2, memo);
return memo[n];
}

public static void main(String[] args) {
System.out.println("Climbing Stairs (Memoization):");

for (int i = 1; i <= 20; i++) {
System.out.println("n = " + i + ", yollar = " + climbStairs(i));
}

// Clear memo for performance test
memo.clear();

// Performance test
long startTime = System.currentTimeMillis();
int result = climbStairs(100);
long endTime = System.currentTimeMillis();

System.out.println("\nn = 100, yollar = " + result);
System.out.println("Vaxt: " + (endTime - startTime) + " ms");
}
}

Mürəkkəblik:

  • Time Complexity: O(n) - Hər dəyər yalnız bir dəfə hesablanır
  • Space Complexity: O(n) - Memo table və rekursiya stack-i

3. Tabulation (Bottom-Up DP)

Koda bax
public class ClimbingStairsTabulation {

public static int climbStairs(int n) {
if (n <= 2) {
return n;
}

// Create DP table
int[] dp = new int[n + 1];

// Base cases
dp[1] = 1; // 1 way to reach step 1
dp[2] = 2; // 2 ways to reach step 2

// Fill table bottom-up
for (int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}

return dp[n];
}

// Method to get all ways for steps 1 to n
public static int[] getAllWays(int n) {
if (n <= 0) return new int[0];

int[] ways = new int[n + 1];

if (n >= 1) ways[1] = 1;
if (n >= 2) ways[2] = 2;

for (int i = 3; i <= n; i++) {
ways[i] = ways[i - 1] + ways[i - 2];
}

return ways;
}

public static void main(String[] args) {
System.out.println("Climbing Stairs (Tabulation):");

// Get all ways
int[] ways = getAllWays(20);
for (int i = 1; i < ways.length; i++) {
System.out.println("n = " + i + ", yollar = " + ways[i]);
}

// Performance test
long startTime = System.currentTimeMillis();
int result = climbStairs(100);
long endTime = System.currentTimeMillis();

System.out.println("\nn = 100, yollar = " + result);
System.out.println("Vaxt: " + (endTime - startTime) + " ms");
}
}

Mürəkkəblik:

  • Time Complexity: O(n)
  • Space Complexity: O(n) - DP table üçün

4. Space Optimized (O(1) Space)

Koda bax
public class ClimbingStairsOptimized {

public static int climbStairs(int n) {
if (n <= 2) {
return n;
}

int prev2 = 1; // ways(1)
int prev1 = 2; // ways(2)
int current = 0;

for (int i = 3; i <= n; i++) {
current = prev1 + prev2;
prev2 = prev1;
prev1 = current;
}

return current;
}

// Alternative implementation with clearer variable names
public static int climbStairsClear(int n) {
if (n <= 2) return n;

int oneStepBefore = 2; // ways(n-1)
int twoStepsBefore = 1; // ways(n-2)

for (int i = 3; i <= n; i++) {
int current = oneStepBefore + twoStepsBefore;
twoStepsBefore = oneStepBefore;
oneStepBefore = current;
}

return oneStepBefore;
}

public static void main(String[] args) {
System.out.println("Climbing Stairs (Space Optimized):");

for (int i = 1; i <= 20; i++) {
System.out.println("n = " + i + ", yollar = " + climbStairs(i));
}

// Performance test
long startTime = System.currentTimeMillis();
int result = climbStairs(100);
long endTime = System.currentTimeMillis();

System.out.println("\nn = 100, yollar = " + result);
System.out.println("Vaxt: " + (endTime - startTime) + " ms");
}
}

Mürəkkəblik:

  • Time Complexity: O(n)
  • Space Complexity: O(1) - Yalnız bir neçə dəyişən

5. Genişləndirilmiş Versiya (k Addım)

Koda bax
public class ClimbingStairsKSteps {

// Hər dəfə 1-dən k-ya qədər pillə qalxa bilərsinizsə
public static int climbStairsK(int n, int k) {
if (n <= 1) {
return 1;
}

int[] dp = new int[n + 1];
dp[0] = 1; // 0-cı pilləyə çatmağın 1 yolu var (başlanğıc)

for (int i = 1; i <= n; i++) {
// i-ci pilləyə (i-1), (i-2), ..., (i-k) pillələrdən gələ bilərik
for (int j = 1; j <= k && j <= i; j++) {
dp[i] += dp[i - j];
}
}

return dp[n];
}

// Space optimized version
public static int climbStairsKOptimized(int n, int k) {
if (n <= 1) return 1;

// Sliding window approach
int[] window = new int[k];
window[0] = 1; // ways(1)

int sum = 1;

for (int i = 2; i <= n; i++) {
int newWays = sum;

if (i <= k) {
newWays += 1; // can reach from step 0
} else {
sum -= window[i % k]; // remove oldest
}

sum += newWays;
window[i % k] = newWays;
}

return window[(n - 1) % k];
}

public static void main(String[] args) {
System.out.println("Climbing Stairs with K Steps:");

int n = 10;
for (int k = 1; k <= 5; k++) {
System.out.println("n = " + n + ", k = " + k + ", yollar = " + climbStairsK(n, k));
}

System.out.println("\nNümunə: n = 5, k = 3");
System.out.println("Yollar = " + climbStairsK(5, 3));
}
}

Mürəkkəblik:

  • Time Complexity: O(n*k)
  • Space Complexity: O(n) və ya O(k) optimized versiyada

Practical Nümunə

Koda bax
public class ClimbingStairsWithCost {

// Hər pilləyə qalxmağın bir dəyəri var
// Minimum dəyərlə zirvəyə çatın
// LeetCode 746: Min Cost Climbing Stairs

public static int minCostClimbingStairs(int[] cost) {
int n = cost.length;

if (n <= 1) {
return 0;
}

// dp[i] = i-ci pilləyə çatmağın minimum dəyəri
int[] dp = new int[n];
dp[0] = cost[0];
dp[1] = cost[1];

for (int i = 2; i < n; i++) {
dp[i] = cost[i] + Math.min(dp[i - 1], dp[i - 2]);
}

// Zirvəyə son pillədən və ya ondan əvvəlki pillədən çata bilərik
return Math.min(dp[n - 1], dp[n - 2]);
}

// Space optimized version
public static int minCostOptimized(int[] cost) {
int n = cost.length;

if (n <= 1) return 0;

int prev2 = cost[0];
int prev1 = cost[1];

for (int i = 2; i < n; i++) {
int current = cost[i] + Math.min(prev1, prev2);
prev2 = prev1;
prev1 = current;
}

return Math.min(prev1, prev2);
}

public static void main(String[] args) {
System.out.println("Min Cost Climbing Stairs:");

int[] cost1 = {10, 15, 20};
System.out.println("Cost array: [10, 15, 20]");
System.out.println("Minimum cost: " + minCostClimbingStairs(cost1));

int[] cost2 = {1, 100, 1, 1, 1, 100, 1, 1, 100, 1};
System.out.println("\nCost array: [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]");
System.out.println("Minimum cost: " + minCostClimbingStairs(cost2));
}
}

Performance Müqayisəsi

Koda bax
public class ClimbingStairsComparison {

public static void comparePerformance() {
int[] testCases = {10, 20, 30, 40, 50};

System.out.println("Performance Müqayisəsi:");
System.out.println("n\tNaive\t\tMemo\t\tTabulation\tOptimized");

for (int n : testCases) {
System.out.print(n + "\t");

// Naive (only for small n)
if (n <= 40) {
long start = System.nanoTime();
ClimbingStairsNaive.climbStairs(n);
long end = System.nanoTime();
System.out.print((end - start) / 1000 + "μs\t\t");
} else {
System.out.print("Too slow\t");
}

// Memoization
long start = System.nanoTime();
ClimbingStairsMemoization.climbStairs(n);
long end = System.nanoTime();
System.out.print((end - start) / 1000 + "μs\t\t");

// Tabulation
start = System.nanoTime();
ClimbingStairsTabulation.climbStairs(n);
end = System.nanoTime();
System.out.print((end - start) / 1000 + "μs\t\t");

// Optimized
start = System.nanoTime();
ClimbingStairsOptimized.climbStairs(n);
end = System.nanoTime();
System.out.print((end - start) / 1000 + "μs");

System.out.println();
}
}

public static void main(String[] args) {
comparePerformance();
}
}

Müsahibə Sualları

1. Əsas Problem

Sual: n pilləyə qalxmaq üçün neçə yol var? (hər dəfə 1 və ya 2 pillə) Cavab: Space optimized DP - O(n) time, O(1) space.

2. K Addım Variantı

Sual: Hər dəfə 1-dən k-ya qədər pillə qalxa bilərsinizsə? Cavab: dp[i] = sum(dp[i-1] + dp[i-2] + ... + dp[i-k])

3. Minimum Dəyər

Sual: Hər pilləyə qalxmağın dəyəri varsa, minimum dəyərlə necə qalxırıq? LeetCode: Problem 746 - Min Cost Climbing Stairs

4. Məhdudiyyətlər

Sual: Bəzi pillələr qırılıbsa və oradan keçə bilmirsinizsə? Cavab: DP-də həmin indeksləri 0 olaraq qeyd etmək.

5. Konkret Yolun Tapılması

Sual: Yalnız sayı deyil, konkret yolları necə tapmaq olar? Cavab: Backtracking və ya path reconstruction istifadə etmək.

LeetCode Problemləri

  1. 70. Climbing Stairs - https://leetcode.com/problems/climbing-stairs/ (Əsas problem)

  2. 746. Min Cost Climbing Stairs - https://leetcode.com/problems/min-cost-climbing-stairs/ (Dəyər əlavə edilib)

  3. 1137. N-th Tribonacci Number - https://leetcode.com/problems/n-th-tribonacci-number/ (3 addım variantı)

  4. 91. Decode Ways - https://leetcode.com/problems/decode-ways/ (Oxşar DP pattern)

  5. 1269. Number of Ways to Stay in the Same Place - https://leetcode.com/problems/number-of-ways-to-stay-in-the-same-place-after-some-steps/ (Daha mürəkkəb variant)

Real-World Tətbiqləri

  1. Path Planning: Robot hərəkət planlaması
  2. Game Development: Oyunçunun hərəkət variantları
  3. Resource Allocation: Addım-addım resurs bölgüsü
  4. Financial Planning: İnvestisiya strategiyaları (mərhələli)
  5. Network Routing: Şəbəkədə alternativ yollar

Optimizasiya Məsləhətləri

  1. Böyük n üçün: Space optimized version istifadə edin
  2. Çoxlu sorğu: Tabulation ilə pre-compute edin
  3. K addım variantı: Sliding window texnikası
  4. Modular arithmetic: Overflow-dan qaçınmaq üçün
  5. Path reconstruction: Əlavə array ilə konkret yolu saxlamaq

Əlaqəli Problemlər

  • Fibonacci Numbers
  • House Robber
  • Decode Ways
  • Jump Game
  • Unique Paths