此题是会员专属,英文版题目链接1274. Number of Ships in a Rectangle
(This problem is an interactive problem.)
Each ship is located at an integer point on the sea represented by a cartesian plane,
and each integer point may contain at most 1 ship.
You have a function Sea.hasShips(topRight, bottomLeft) which takes two points as arguments and
returns true If there is at least one ship in the rectangle represented by the two points, including
on the boundary.
Given two points: the top right and bottom left corners of a rectangle, return the number
of ships present in that rectangle. It is guaranteed that there are at most 10 ships in that rectangle.
Submissions making more than 400 calls to hasShips will be judged Wrong Answer.
Also, any solutions that attempt to circumvent the judge will result in disqualification.
Example :
Input:
ships = [[1,1],[2,2],[3,3],[5,5]], topRight = [4,4], bottomLeft = [0,0]
Output: 3
Explanation: From [0,0] to [4,4] we can count 3 ships within the range.
Constraints:
On the input ships is only given to initialize the map internally. You must solve
this problem "blindfolded". In other words, you must find the answer using the given hasShips API,
without knowing the ships position.
·0 <= bottomLeft[0] <= topRight[0] <= 1000
·0 <= bottomLeft[1] <= topRight[1] <= 1000
·topRight != bottomLeft
优化前的方法:
很容易想到的方法是把一个矩形四分,然后对每一部分再进行划分,直到只剩一个点,然后判断这个点上是否有船。 这里不必担心超出题目所给的函数调用400次的限制条件,因为船只数量限定在10个。
但是会出现重复计算的问题,比如中间的一个点会在划分的四个子矩形内个被计算一次,总共是四次,而端点只会被计算一次,边上的点(非端点)会被计算两次,为了得到正确答案,我们在判断某个点上是否有船的时候还需判断这个点的位置——在端点返回4,在边上返回2,在中心返回1, 这样最后得到的结果除以4就可以得到正确结果。
/**
* // This is Sea's API interface.
* // You should not implement it, or speculate about its implementation
* class Sea {
* public:
* bool hasShips(vector<int> topRight, vector<int> bottomLeft);
* };
*/
class Solution {
public:
vector<int> inittop, initbottom;
bool online(vector<int> pos){
if(pos[0] == inittop[0] || pos[0] == initbottom[0] || pos[1] == inittop[1] || pos[1] == initbottom[1])
return true;
return false;
}//判断是否在边界
bool onpron(vector<int> pos){
if((pos[0] == inittop[0] || pos[0] == initbottom[0])&& (pos[1] == inittop[1] || pos[1] == initbottom[1]))
return true;
return false;
} //判断是否在顶点
int countShips1(Sea sea, vector<int> topRight, vector<int> bottomLeft) {
//四分
if(topRight[0] == bottomLeft[0] && topRight[1] == bottomLeft[1]) {
if(!sea.hasShips(topRight,bottomLeft)) return 0;
if(onpron(bottomLeft))
return 4;
else if(online(bottomLeft))
return 2;
else
return 1;
}
if(!sea.hasShips(topRight, bottomLeft))return 0;
int sum = 0;
int x = (topRight[0] + bottomLeft[0])/2;
int y = (topRight[1] + bottomLeft[1])/2;
if(x == bottomLeft[0]){
if(y == bottomLeft[1]){
sum += countShips1(sea, bottomLeft, bottomLeft);
sum += countShips1(sea, topRight, topRight);
sum += countShips1(sea,vector<int>({bottomLeft[0],topRight[1]}),vector<int>({bottomLeft[0],topRight[1]}));
sum += countShips1(sea,vector<int>({topRight[0],bottomLeft[1]}), vector<int>({topRight[0],bottomLeft[1]}));
}else{
sum += countShips1(sea, topRight, vector<int>({x, y}));//2
sum += countShips1(sea, vector<int>({topRight[0], y}), vector<int>({x, bottomLeft[1]}));//4
}
}else{
if(y == bottomLeft[1]){
sum += countShips1(sea, vector<int>({x, topRight[1]}), vector<int>({bottomLeft[0], y}));//1
sum += countShips1(sea, topRight, vector<int>({x, y}));//2
}else{
sum += countShips1(sea, vector<int>({x, topRight[1]}), vector<int>({bottomLeft[0], y}));//1
sum += countShips1(sea, vector<int>({topRight[0], y}), vector<int>({x, bottomLeft[1]}));//4
sum += countShips1(sea, vector<int>({x, y}), bottomLeft);//3
sum += countShips1(sea, topRight, vector<int>({x, y}));//2
}
}
return sum;
}
int countShips(Sea sea, vector<int> topRight, vector<int> bottomLeft) {
inittop = topRight;
initbottom = bottomLeft;
return countShips1(sea, topRight, bottomLeft)/4;
}
};
优化后的方法
上述解法还涉及到对边长为1的矩形的划分问题,实在是过于麻烦,然后我在提交中看到了大佬8ms的解法——把一个矩形拆分成左下的一个子矩形,上方的一条直线,右边的一条直线和右上角的一个点。 这样避免了点被重复判断的问题。
class Solution {
private:
int search(Sea &sea, int top, int right, int bottom, int left) {
if (top == bottom && right == left) {
return sea.hasShips(vector<int>{top, right}, vector<int>{bottom, left});
} else {
int midv = (top + bottom) / 2, midh = (left + right) / 2;
int result = 0;
if (sea.hasShips(vector<int>{midv, midh}, vector<int>{bottom, left})) {
result += search(sea, midv, midh, bottom, left);
}
if (midv < top && sea.hasShips(vector<int>{top, midh},
vector<int>{midv + 1, left})) {
result += search(sea, top, midh, midv + 1, left);
}
if (midh < right && sea.hasShips(vector<int>{midv, right},
vector<int>{bottom, midh + 1})) {
result += search(sea, midv, right, bottom, midh + 1);
}
if (midv < top && midh < right &&
sea.hasShips(vector<int>{top, right}, vector<int>{midv+1, midh+1})) {
result += search(sea, top, right, midv + 1, midh + 1);
}
return result;
}
}
public:
int countShips(Sea sea, vector<int> topRight, vector<int> bottomLeft) {
return search(sea, topRight[0], topRight[1], bottomLeft[0], bottomLeft[1]);
}
};