Last active
April 2, 2023 12:25
-
-
Save optimistiks/4ffbddd64924b1b0ff5e229ef45b3e7a to your computer and use it in GitHub Desktop.
Find maximum possible capital
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// c is my capital | |
// k is times I want to invest | |
// capitals is list of min capitals of projects to invest | |
// profits is how much profit a project brings | |
export function maximumCapital(c, k, capitals, profits) { | |
// in this heap we are going to store capitals that | |
// are required by projects to invest into them | |
// top element is always the cheapest project to invest to | |
const capHeap = new TupleHeap(); | |
// in this heap we're going to store profits of projects | |
// that we can afford to invest to | |
// so project is either present in the capitals heap (above) | |
// or in this profits heap, but not both | |
const profitHeap = new TupleHeap(); | |
// push capitals required by projects to heap | |
capitals.forEach((cap, index) => capHeap.push([cap, index])); | |
// hold our total capital in a variable | |
// we will be adding profits of projects here | |
let myCap = c; | |
// hold how many times we've invested | |
// we stop investing when count reaches k | |
let count = 0; | |
// invest in project no more than k times | |
// if there are no projects to invest, but count < k, | |
// we just increment count | |
while (count < k) { | |
while (capHeap.length() > 0) { | |
// look at the smallest project capital to invest (heap top) | |
const [cap, index] = capHeap.peekTop(); | |
if (cap > myCap) { | |
// if we can't invest into the cheapest project, | |
// means we cannot invest in any other project, | |
// since all other projects are more expensive | |
break; | |
} | |
// remove the smallest project capital from the heap | |
// the second smallest will take its place | |
capHeap.deleteTop(); | |
// push the project profit into the profits heap | |
// we make the value negative so we dont need to implement | |
// a separate max heap | |
profitHeap.push([-profits[index], index]); | |
} | |
// at this point we've removed all projects that we can afford | |
// from the capitals heap, | |
// and added their profits to the profits heap | |
// now we need to pick the top element from the profits heap | |
// this will be the project that brings the most profit | |
// out of all projects that we can afford at this step | |
if (profitHeap.length() > 0) { | |
const [profit] = profitHeap.deleteTop(); | |
// increase our total capital by adding the projects profit | |
myCap = myCap - profit; | |
// at this point our total capital is increased, | |
// and on the next iteration we might afford more projects | |
// from the capitals heap | |
} | |
// at this point we've either invested in a project, | |
// or there were no projects we can afford to invest to, | |
// increase our count anyway | |
count += 1; | |
} | |
return myCap; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Heap { | |
heap = []; | |
getValue(index) { | |
return this.heap[index]; | |
} | |
getParentIndex(i) { | |
return Math.floor(i / 2); | |
} | |
getLeftChildIndex(i) { | |
return i * 2 + 1; | |
} | |
getRightChildIndex(i) { | |
return i * 2 + 2; | |
} | |
deleteTop() { | |
const top = this.heap[0]; | |
const last = this.heap.pop(); | |
if (this.heap.length === 0) { | |
return top; | |
} | |
this.heap[0] = last; | |
this.bubbleDown(0); | |
return top; | |
} | |
peekTop() { | |
return this.heap[0]; | |
} | |
bubbleUp(index) { | |
if (index === 0) { | |
return; | |
} | |
const value = this.getValue(index); | |
const parentIndex = this.getParentIndex(index); | |
const parent = this.getValue(parentIndex); | |
if (value < parent) { | |
const parent = this.heap[parentIndex]; | |
this.heap[parentIndex] = this.heap[index]; | |
this.heap[index] = parent; | |
this.bubbleUp(parentIndex); | |
} | |
} | |
bubbleDown(index) { | |
const value = this.getValue(index); | |
const leftChildIndex = this.getLeftChildIndex(index); | |
const rightChildIndex = this.getRightChildIndex(index); | |
const leftChild = this.getValue(leftChildIndex); | |
const rightChild = this.getValue(rightChildIndex); | |
const lInf = leftChild ?? Infinity; | |
const rInf = rightChild ?? Infinity; | |
// if min heap property is satisified, nothing to do | |
// each child is greater than parent | |
if (lInf > value && rInf > value) { | |
return; | |
} | |
// min heap prop is not satisfied, swap with smallest child | |
const smallestChildIndex = lInf <= rInf ? leftChildIndex : rightChildIndex; | |
const child = this.heap[smallestChildIndex]; | |
this.heap[smallestChildIndex] = this.heap[index]; | |
this.heap[index] = child; | |
this.bubbleDown(smallestChildIndex); | |
} | |
getHeap() { | |
return this.heap; | |
} | |
push(value) { | |
this.heap.push(value); | |
this.bubbleUp(this.heap.length - 1); | |
} | |
print() { | |
console.log("print:"); | |
this.heap.forEach((item, index) => { | |
const children = [ | |
this.heap[this.getLeftChildIndex(index)], | |
this.heap[this.getRightChildIndex(index)], | |
]; | |
if (children.filter(Boolean).length > 0 || index === 0) { | |
console.log("node", item, "children", children, "index", index); | |
} | |
}); | |
} | |
length() { | |
return this.heap.length; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class TupleHeap extends Heap { | |
getValue(index) { | |
return this.heap[index] ? this.heap[index][0] : null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment