diff --git a/Dynamic Programming/DP on State Transition/Find_no_of_way_to_reach_kth_stair/Markdown.md b/Dynamic Programming/DP on State Transition/Find_no_of_way_to_reach_kth_stair/Markdown.md new file mode 100644 index 00000000..4b1399a6 --- /dev/null +++ b/Dynamic Programming/DP on State Transition/Find_no_of_way_to_reach_kth_stair/Markdown.md @@ -0,0 +1,112 @@ +# Problem — Find Number of Ways to Reach the K-th Stair - Hard Problem + +## Problem Summary + +You are given a non-negative integer `k`. +There is an infinite staircase with the lowest stair numbered `0`. + +Suppose ,Alice starts on stair **1** with an initial `jump = 0`. +She wants to reach stair **k** using the following two operations: + +1. **Go Down:** + - Move from stair `i` → `i - 1`. + - ⚠️ Cannot be used **consecutively** or when `i = 0`. + +2. **Go Up:** + - Move from stair `i` → `i + 2^jump`. + - After that, set `jump = jump + 1`. + +Return the total **number of ways** Alice can reach stair `k`. + +--- + +## Key Observations to be Noted + +- Movement depends not only on **position** but also on the **current jump value**. +- Since down moves cannot be consecutive, we also need to track the **last move** type. +- Therefore, each *state* is described by **three parameters**. + +--- + +## DP State Definition + +Let +``` +dp[i][jump][prevDown] = number of ways to reach stair i + with current jump = jump + and previous move was 'down' or not. +``` + +Where: +- `i` → current stair number +- `jump` → current jump value +- `prevDown` → 0 if previous move was up, 1 if previous move was down + +--- +## DP Transitions +1. **Go Up** + ``` + nextStair = i + 2^jump + dp[nextStair][jump + 1][0] += dp[i][jump][prevDown] + ``` + +2. **Go Down** (only if previous move was not down) + ``` + if prevDown == 0 and i > 0: + dp[i - 1][jump][1] += dp[i][jump][prevDown] + ``` + +--- + +## Base Case +``` +dp[1][0][0] = 1 # Alice starts on stair 1 with jump = 0, last move not down +``` +for solving this problem, i have used the recursion with memoization.. +--- + +## Type and Category +| Aspect | Type | +|----------------------|--------------------------------------------------------------| +| **DP Dimension** | 3D DP (`position`, `jump`, `prevDown`) | +| **Category** | State-Transition DP / Simulation DP | +| **Pattern Type** | DP with constrained transitions | +| **Related Problems** | Frog Jump , Number of Ways to Reach Target (LC 2585) | + +--- + +## ⏱️ Time and Space Complexity +Let `maxJump` ≈ `log2(k)` (since jump grows exponentially). + +| Complexity | Value | +|-------------|--------------| +| **Time** | O(k * log k) | +| **Space** | O(k * log k) | + +--- +## 🧩 Example +### Input +``` +k = 3 +``` +### Possible Sequences +1. **Start(1, jump=0)** → Up → `(3, jump=1)` ✅ + → Alice reached 3 directly. + +2. **Start(1)** → Up → `(3)` → Down → `(2)` → Up → `(4)` → Down → `(3)` ✅ + → Reached 3 again via multiple steps. + +Hence, total ways = 2. +--- + +## 📘 Summary + +| Concept | Description | +|--------------------|---------------------------------------------------------| +| **Problem Type** | DP with movement and state constraints | +| **DP Dimensions** | 3 (position, jump, previous move) | +| **Main Challenge** | Non-consecutive down restriction & exponential up jumps | +| **Approach** | State-transition DP | +| **Complexity** | O(k * log k) | + +--- \ No newline at end of file diff --git a/Dynamic Programming/DP on State Transition/Find_no_of_way_to_reach_kth_stair/kth_stair.cpp b/Dynamic Programming/DP on State Transition/Find_no_of_way_to_reach_kth_stair/kth_stair.cpp new file mode 100644 index 00000000..3df61652 --- /dev/null +++ b/Dynamic Programming/DP on State Transition/Find_no_of_way_to_reach_kth_stair/kth_stair.cpp @@ -0,0 +1,33 @@ +#include +using namespace std; + +class Solution { +public: + int waysToReachStair(int k) + { + // Variable to store total number of ways to reach stair k + long num_ways = 0; + // Loop over possible number of "up" jumps covering all cases for combination. + for (int i = 0; i <= 31; i++) + { + // After i jumps, total up moves = i + 1 + int num_jumps = i + 1; + long long stairs_covered_back = (1LL << i) - k; + + if (0 > stairs_covered_back || i + 1 < stairs_covered_back) + continue; + // Now we need to count number of valid sequences of "up" and "down" operations that result in total displacement + // among total possible move slots. now Compute nCr using its formula. + long long ways = 1; + for (int j = 1; j <= stairs_covered_back; j++) + { + // Multiplying in iterative form to avoid factorial overflow + ways *= (num_jumps - j + 1); + ways = ways / j; + } + // Add to total number of ways + num_ways += ways; + } + return (int)num_ways; + } +}; diff --git a/Dynamic Programming/DP on State Transition/Find_no_of_way_to_reach_kth_stair/kth_stair.java b/Dynamic Programming/DP on State Transition/Find_no_of_way_to_reach_kth_stair/kth_stair.java new file mode 100644 index 00000000..d23d331b --- /dev/null +++ b/Dynamic Programming/DP on State Transition/Find_no_of_way_to_reach_kth_stair/kth_stair.java @@ -0,0 +1,44 @@ +class Solution +{ + HashMap mp; + long[] power; + int K; + + int solve(int i, int jump, int canGoBack) + { + if (i > K + 1) + return 0; + + String key = i + "_" + jump + "_" + canGoBack; + + if (mp.containsKey(key)) + return mp.get(key); + + int count = 0; + + if (i == K) { + count++; + } + + if (canGoBack == 1) { + count += solve(i - 1, jump, 0); + } + + count += solve(i + (int) power[jump], jump + 1, 1); + + mp.put(key, count); + return count; + } + + public int waysToReachStair(int k) { + mp = new HashMap<>(); + power = new long[33]; + K = k; + + for (int i = 0; i < 33; ++i) { + power[i] = (long) Math.pow(2, i); + } + + return solve(1, 0, 1); + } +} diff --git a/Matrix/Kth Smallest element in table/Markdown.md b/Matrix/Kth Smallest element in table/Markdown.md new file mode 100644 index 00000000..4bb9953a --- /dev/null +++ b/Matrix/Kth Smallest element in table/Markdown.md @@ -0,0 +1,51 @@ +# Problem— Kth Smallest Number in Multiplication Table + +## 📄 Problem Statement + +You are given two positive integers `m` and `n`, which define an `m × n` multiplication table: the value at cell `(i, j)` (1-indexed) is `i * j`. + +Given a positive integer `k`, return the k-th smallest number in this multiplication table (when all the `m × n` values are written in a sorted order, counting duplicates). + +### Constraints / Details + +- `m, n` can be up to **3 × 10⁴** +- `k` can be up to **10⁹** +- The multiplication table has **m * n** entries (potentially up to ∼9×10⁸) +- Sorting all elements explicitly would be computationally expensive or infeasible for large sizes + +--- + +## 🧠 Key Insights & Approach + +1. **Monotonicity & counting** + - In any sorted list, the k-th smallest element `x` is such that **exactly `k` values ≤ `x`** in the table. + - For a candidate value `X`, you can **count how many table entries ≤ `X`** by summing, for each row `i` (from 1 to `m`), + `min(n, floor(X / i))`. + - Use that count to guide a **binary search** over possible values of `X`. + +2. **Search space** + - The **smallest** possible value is `1 * 1 = 1`. + - The **largest** possible value is `m * n` (i.e. the bottom-right corner of the table). + - Use binary search between 1 and `m * n` (or between 1 and `m * n`, or max possible product) to find the smallest `X` such that **count(≤ X) ≥ k**. + +3. **Correctness & termination** + - Because counting function is non-decreasing in `X`, binary search will home in on the correct threshold. + - The final `X` found is the **k-th smallest**. + +--- + +## ✅ Example Cases + +| Example | Input | Output | Explanation | +|-------- |-------|--------|-------------| +| 1 | `m = 3`, `n = 3`, `k = 5` | `3` | The 3×3 table is: 1,2,3; 2,4,6; 3,6,9 → sorted: 1,2,2,3,3,4,6,6,9 → the 5th element is 3 | +| 2 | `m = 2`, `n = 3`, `k = 6` | `6` | The table is: 1,2,3; 2,4,6 → sorted: 1,2,2,3,4,6 → 6 is the 6th element | + +--- + +## ⚙️ Time & Space Complexity + +| Metric | Complexity | +|---------- |-------------------------| +| **Time** | O((m + n) · log(m · n)) | +| **Space** | O(1) | diff --git a/Matrix/Kth Smallest element in table/kth_smallest.cpp b/Matrix/Kth Smallest element in table/kth_smallest.cpp new file mode 100644 index 00000000..0be2e208 --- /dev/null +++ b/Matrix/Kth Smallest element in table/kth_smallest.cpp @@ -0,0 +1,41 @@ +#include +using namespace std; +class Solution +{ + public: + int findKthNumber(int m, int n, int k) + { + // Binary search on the answer range [1, m*n] + int left = 1; + int right = m * n; + + while (left < right) + { + // Calculate middle value + int mid = left + (right - left) / 2; + + // Count how many numbers in the multiplication table are <= mid + int count = 0; + for (int row = 1; row <= m; ++row) + { + // For each row i, elements are: i*1, i*2, ..., i*n + // Number of elements <= mid in row i is min(mid/i, n) + count += std::min(mid / row, n); + } + + // If count >= k, the kth smallest number is at most mid + if (count >= k) + { + right = mid; + } + + else + { + // Otherwise, the kth smallest number is greater than mid + left = mid + 1; + } + } + // left == right, which is the kth smallest number + return left; + } +}; \ No newline at end of file diff --git a/Matrix/Kth Smallest element in table/kth_smallest.java b/Matrix/Kth Smallest element in table/kth_smallest.java new file mode 100644 index 00000000..1e477abf --- /dev/null +++ b/Matrix/Kth Smallest element in table/kth_smallest.java @@ -0,0 +1,36 @@ +class Solution +{ + public int findKthNumber(int m, int n, int k) { + // Initialize binary search range + // Minimum possible value is 1 (1*1), maximum is m*n + int left = 1; + int right = m * n; + + // Binary search for the kth smallest number + while (left < right) + { + // Calculate middle value using unsigned right shift to avoid overflow + int mid = (left + right) >>> 1; + + // Count how many numbers in the multiplication table are <= mid + int count = 0; + for (int row = 1; row <= m; row++) { + // For each row i, elements are: i*1, i*2, ..., i*n + // Count of elements <= mid in row i is min(mid/i, n) + count += Math.min(mid / row, n); + } + + // Adjust search range based on count + if (count >= k) { + // If count >= k, the kth number is at most mid + right = mid; + } else { + // If count < k, the kth number must be greater than mid + left = mid + 1; + } + } + + // When left == right, we've found the kth smallest number + return left; + } +}