33
loading...
This website collects cookies to deliver better user experience
You are part of a rescue operation for a lost boat in the sea.
You have a radar capable of telling you if a boat is in a specific region.
Your goal is to save the crew by coding a function that will return the location of the boat
true
if the boat is present in the area and false
if not.type Area = {
x: number;
y: number;
width: number;
height: number;
}
type UseRadar = (area: Area) => boolean
const getBoatCoordinates = () => {
for(let x = 0; x < WIDTH; x++) {
for(let y = 0; y < HEIGHT; y++) {
if(useRadar({ x, y, width: 1, height: 1 })) return { x, y };
}
}
}
width = 10
and height = 10
) and that the radar takes 1 minute
to return an answer. We would spend 50 minutes on average checking for the boat ( 0.5 * width * height * radarTime
) which is definitely time enough for our boat to sink with all the crew on it. But don't despair, what if I tell you that we can improve the algorithm so that the time spent looking for the boat will be 7 minutes?const getBoatCoordinatesInArea = (area) => {
// Area is divided in 2
const [area1, area2] = divideArea(area);
// Checks if boat is in first area
if (useRadar(area1)) {
return getBoatCoordinatesInArea(area1);
} else {
return getBoatCoordinatesInArea(area2);
}
};
if
statement, if the boat is in area1
we call the same function with that portion of the sea, if not, then the boat must be in area2
and we call the same function with that chunk.const getBoatCoordinatesInArea = (area) => {
// Exit condition
if (area.width === 1 && area.height === 1) {
return { x: area.x, y: area.y };
}
// Area is divided in 2
const [area1, area2] = divideArea(area);
// Checks if boat is in first area
if (useRadar(area1)) {
return getBoatCoordinatesInArea(area1);
} else {
return getBoatCoordinatesInArea(area2);
}
};
const getBoatCoordinates = () => {
return getBoatCoordinatesInArea({
x: 0,
y: 0,
width: WIDTH,
height: HEIGHT
});
}
log2(width * height)
. Now, with our initial inputs we would need the radar 6.64 times
but since we cannot use it half a time (you use it or you don't) we need to round the number to the next integer which results in 7 times
. This translates into a waiting time of 7 minutes, which gives us enough time to send a rescue boat and save the crew! Hurray!Dimensions | Brute force | Binary search |
---|---|---|
width = 100 height = 100
|
50 minutes | 7 minutes |
width = 200 height = 200
|
200 minutes | 9 minutes |
Increase % | 300% | ~30% |
divideArea
in the code earlier so let's have a look at it here. Since we can divide an area in two axis, we can take 2 different approaches to implement this function. The first one is dividing the area initially on one axis until you reach its limit, for example, you divide vertically until width becomes 1, and then you start dividing on the other axis. The second one is swapping the axis on each iteration, which is a bit more complex since you need to keep track of the divided axis.const divideAreaVertically = ({ x, y, width, height }: Area): [Area, Area] => {
const halfWidth = Math.floor(width / 2);
const leftArea: Area = { x, y, width: halfWidth, height };
const rightArea: Area = {
x: x + halfWidth,
y,
width: width - halfWidth,
height,
};
return [leftArea, rightArea];
};
const divideAreaHorizontally = ({ x, y, width, height }: Area): [Area, Area] => {
const halfHeight = Math.floor(height / 2);
const bottomArea: Area = { x, y, width, height: halfHeight };
const topArea: Area = {
x,
y: y + halfHeight,
width,
height: height - halfHeight,
};
return [bottomArea, topArea];
};
const divideArea = (area: Area): [Area, Area] => {
if(area.width > 1) return divideAreaVertically(area);
return divideAreaHorizontally(area);
}