function maxNumberOfFittingRectangles(rectangles) {
// Storage of optimal, intermediate results (DP principle),
// keyed by the index of the first rectangle taken
let memo = new Map;
// Take a copy of rectangles, and sort it in order of decreasing width,
// and if there are ties: by decreasing height
rectangles = [...rectangles].sort( (a, b) => (b.width - a.width)
|| (b.height - a.height) );
function recurse(maxHeight, startIndex) {
for (let i = startIndex; i < rectangles.length; i++) {
if (rectangles[i].height <= maxHeight ) { // Can fit
// Try a solution that includes rectangles[i]
// - Only recurse when we did not do this before
if (!(memo.has(i))) memo.set(i, recurse(rectangles[i].height, i+1)+1);
// Also try a solution that excludes rectangles[i], and
// return best of both possibilities:
return Math.max(memo.get(i), recurse(maxHeight, i+1));
}
}
return 0; // recursion's base case
}
let result = recurse(Infinity, 0);
// Display some information for understanding the solution:
for (let i = 0; i < rectangles.length; i++) {
console.log(JSON.stringify(rectangles[i]),
'if taken as first: solution = ', memo.get(i));
}
return result;
}
// Sample data
let rectangles = [
{ width: 10, height: 8 },
{ width: 6, height: 12 },
{ width: 4, height: 9 },
{ width: 9, height: 9 },
{ width: 2, height: 9 },
{ width: 11, height: 4 },
{ width: 9, height: 5 },
{ width: 8, height: 11 },
{ width: 6, height: 6 },
{ width: 5, height: 8 },
{ width: 2, height: 7 },
{ width: 3, height: 5 },
{ width: 12, height: 7 },
];
let result = maxNumberOfFittingRectangles(rectangles);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }