diff --git a/dsa-solutions/lc-solutions/0500-0599/0502-IPO.md b/dsa-solutions/lc-solutions/0500-0599/0502-IPO.md new file mode 100644 index 000000000..5aaaa99b7 --- /dev/null +++ b/dsa-solutions/lc-solutions/0500-0599/0502-IPO.md @@ -0,0 +1,292 @@ +--- +id: IPO +title: IPO +sidebar_label: IPO +tags: + - Dynamic Programming + - Greedy Algorithm + - Priority Queue +--- + +## Problem Description + +| Problem Statement | Solution Link | LeetCode Profile | +| :------------------------------------------------------ | :------------------------------------------------------------------------- | :------------------------------------------------------ | +| [IPO](https://leetcode.com/problems/IPO/description/) | [IPO Solution on LeetCode](https://leetcode.com/problems/IPO/solutions/) | [Nikita Saini](https://leetcode.com/u/Saini_Nikita/) | + +## Problem Description + +You are given `n` projects where the ith project has a pure profit `profits[i]` and a minimum capital of `capital[i]` is needed to start it. Initially, you have `w` capital. When you finish a project, you obtain its pure profit, which is added to your total capital. + +Your goal is to pick a list of at most `k` distinct projects to maximize your final capital. + +## Constraints + +- `1 <= k <= 10^5` +- `0 <= w <= 10^9` +- `1 <= n <= 10^5` +- `0 <= profits[i] <= 10^4` +- `0 <= capital[i] <= 10^9` + +## Approach + +The problem can be approached using a combination of greedy strategy and efficient data structures: +1. **Priority Queue (Max-Heap)**: Use a max-heap to always select the project with the maximum profit that can be started with the current capital. +2. **Sorting**: Sort projects based on their capital requirements. +3. **Iterative Selection**: Iterate up to `k` times (or until no more projects can be started) to select the project with the highest profit that can be started with the current capital. + +### Solution in Different languages + +## Solution in Python + +```python +import heapq + +def findMaximizedCapital(k, w, profits, capital): + n = len(profits) + projects = sorted(zip(capital, profits)) # Sort projects by their capital requirements + available_projects = [] + idx = 0 + for _ in range(k): + while idx < n and projects[idx][0] <= w: + heapq.heappush(available_projects, -projects[idx][1]) # Max-heap for profits + idx += 1 + if available_projects: + w -= heapq.heappop(available_projects) # Add the profit from the best project + else: + break + return w + +# Example usage: +k = 2 +w = 0 +profits = [1, 2, 3] +capital = [0, 1, 1] +print(findMaximizedCapital(k, w, profits, capital)) # Output: 4 +``` + +## Solution in Java + +```java +import java.util.PriorityQueue; + +class Solution { + public int findMaximizedCapital(int k, int w, int[] profits, int[] capital) { + int n = profits.length; + int[][] projects = new int[n][2]; + for (int i = 0; i < n; i++) { + projects[i][0] = capital[i]; + projects[i][1] = profits[i]; + } + Arrays.sort(projects, (a, b) -> a[0] - b[0]); // Sort projects by their capital requirements + PriorityQueue maxHeap = new PriorityQueue<>((a, b) -> b - a); + int idx = 0; + for (int i = 0; i < k; i++) { + while (idx < n && projects[idx][0] <= w) { + maxHeap.offer(projects[idx][1]); // Max-heap for profits + idx++; + } + if (!maxHeap.isEmpty()) { + w += maxHeap.poll(); // Add the profit from the best project + } else { + break; + } + } + return w; + } +} +``` + +## Solution in C++ + +```cpp +#include +#include +#include +using namespace std; + +class Solution { +public: + int findMaximizedCapital(int k, int w, vector& profits, vector& capital) { + int n = profits.size(); + vector> projects(n); + for (int i = 0; i < n; ++i) { + projects[i] = {capital[i], profits[i]}; + } + sort(projects.begin(), projects.end()); // Sort projects by their capital requirements + priority_queue maxHeap; + int idx = 0; + for (int i = 0; i < k; ++i) { + while (idx < n && projects[idx].first <= w) { + maxHeap.push(projects[idx].second); // Max-heap for profits + ++idx; + } + if (!maxHeap.empty()) { + w += maxHeap.top(); // Add the profit from the best project + maxHeap.pop(); + } else { + break; + } + } + return w; + } +}; +``` + +## Solution in C + +```c +#include + +// Helper function to sort projects by capital requirement +int compare(const void *a, const void *b) { + int *projA = *(int **)a; + int *projB = *(int **)b; + return projA[0] - projB[0]; +} + +int findMaximizedCapital(int k, int w, int* profits, int profitsSize, int* capital, int capitalSize) { + int n = profitsSize; + int **projects = (int **)malloc(n * sizeof(int *)); + for (int i = 0; i < n; ++i) { + projects[i] = (int *)malloc(2 * sizeof(int)); + projects[i][0] = capital[i]; + projects[i][1] = profits[i]; + } + qsort(projects, n, sizeof(int *), compare); // Sort projects by their capital requirements + int idx = 0; + for (int i = 0; i < k; ++i) { + while (idx < n && projects[idx][0] <= w) { + w += projects[idx][1]; // Add the profit from the best project + ++idx; + } + if (idx == n) break; + } + for (int i = 0; i < n; ++i) { + free(projects[i]); + } + free(projects); + return w; +} +``` + +## Solution in JavaScript + +```javascript +class PriorityQueue { + constructor(comparator = (a, b) => a - b) { + this._heap = []; + this._comparator = comparator; + } + + size() { + return this._heap.length; + } + + isEmpty() { + return this.size() === 0; + } + + peek() { + return this.isEmpty() ? undefined : this._heap[0]; + } + + push(...values) { + values.forEach(value => { + this._heap.push(value); + this._siftUp(); + }); + return this.size(); + } + + pop() { + const poppedValue = this.peek(); + const bottom = this.size() - 1; + if (bottom > 0) { + this._swap(0, bottom); + } + this._heap.pop(); + this._siftDown(); + return poppedValue; + } + + _parent(idx) { + return Math.floor((idx - 1) / 2); + } + + _left(idx) { + return idx * 2 + 1; + } + + _right(idx) { + return idx * 2 + 2; + } + + _swap(i, j) { + [this._heap[i], this._heap[j]] = [this._heap[j], this._heap[i]]; + } + + _greater(i, j) { + return this._comparator(this._heap[i], this._heap[j]) < 0; + } + + _siftUp() { + let node = this.size() - 1; + while (node > 0 && this._greater(node, this._parent(node))) { + this._swap(node, this._parent(node)); + node = this._parent(node); + } + } + + _siftDown() { + let node = 0; + while ( + (this._left(node) < this.size() && this._greater(this._left(node), node)) || + (this._right(node) < this.size() && this._greater(this._right(node), node)) + ) { + let maxChild = (this._right(node) < this.size() && this._greater(this._right(node), this._left(node))) ? this._right(node) : this._left(node); + this._swap(node, maxChild); + node = maxChild; + } + } +} + +var findMaximizedCapital = function(k, w, profits, capital) { + const n = profits.length; + const projects = []; + for (let i = 0; i < n; i++) { + projects.push([capital[i], profits[i]]); + } + projects.sort((a, b) => a[0] - b[0]); // Sort projects by their capital requirements + const maxHeap = new PriorityQueue((a, b) => b - a); + let idx = 0; + for (let i = 0; i < k; i++) { + while (idx < n && projects[idx][0] <= w) { + maxHeap.push(projects[idx][1]); // Max-heap for profits + idx++; + } + if (!maxHeap.isEmpty()) { + w += maxHeap.pop(); // Add the profit from the best project + } else { + break; + } + } + return w; +}; +``` + +## Step-by-Step Algorithm + +1. **Input Parsing**: Convert input data into appropriate data structures (arrays, lists, or vectors). +2. **Sorting**: Sort projects based on their capital requirements. +3. **Priority Queue Initialization**: Initialize a max-heap (priority queue) to keep track of the most profitable projects that can be started with the current capital. +4. **Iterative Selection**: + - For up to `k` times, iterate through the sorted projects. + - Push all feasible projects (capital requirement <= current capital) into the max-heap. + - If the max-heap is not empty, pop the project with the maximum profit and add its profit to the current capital. + - Break the loop if no more projects can be started. +5. **Return Result**: Return the current capital after selecting up to `k` projects. + +## Conclusion + +The provided solutions efficiently solve the problem of selecting at most `k` projects to maximize capital using a combination of greedy strategy and priority queues. This approach ensures that the solution is optimal and runs within acceptable time limits for the given constraints.