Java 在给定的N个点中包含K个点的最小面积正方形
这个问题是在一次在线测试中问我的。 笛卡尔平面上有N个点。将给出一个整数K。 目的是找到包含至少K个点的正方形(最小值)的面积。 正方形的边应该平行于轴。正方形的顶点应该是整数。位于侧面的任何点都不被视为在正方形内 我只能解K=N(即所有点都位于正方形中) 我的解决办法是——Java 在给定的N个点中包含K个点的最小面积正方形,java,algorithm,Java,Algorithm,这个问题是在一次在线测试中问我的。 笛卡尔平面上有N个点。将给出一个整数K。 目的是找到包含至少K个点的正方形(最小值)的面积。 正方形的边应该平行于轴。正方形的顶点应该是整数。位于侧面的任何点都不被视为在正方形内 我只能解K=N(即所有点都位于正方形中) 我的解决办法是—— static int minarea(int[] x, int[] y, int k) { //Find max y int maxVal = Integer.MIN_VALUE; for(
static int minarea(int[] x, int[] y, int k) {
//Find max y
int maxVal = Integer.MIN_VALUE;
for(int i : y){
if(i > maxVal){
maxVal = i;
}
}
//Find min y
int minVal = Integer.MAX_VALUE;
for(int i : x){
if(i < minVal){
minVal = i;
}
}
int yLength = (maxVal-minVal)+2;
//Find max x
maxVal = Integer.MIN_VALUE;
for(int i : x){
if(i > maxVal){
maxVal = i;
}
}
//Find min x
minVal = Integer.MAX_VALUE;
for(int i : x){
if(i < minVal){
minVal = i;
}
}
int xLength = (maxVal-minVal)+2;
int sqSide = (yLength > xLength)?yLength:xLength;
return sqSide*sqSide;
}
static int minarea(int[]x,int[]y,int k){
//找到max y
int maxVal=整数.MIN_值;
for(int i:y){
如果(i>maxVal){
maxVal=i;
}
}
//找到Miny
int minVal=Integer.MAX_值;
for(int i:x){
如果(imaxVal){
maxVal=i;
}
}
//查找最小x
最小值=整数。最大值;
for(int i:x){
如果(iX长)?叶长:X长;
返回sqSide*sqSide;
}
通解的一种方法是在N个点中找到K个点的所有可能组合,并对所有组合应用上述方法,但这并不好。请告知。可以看出,我们始终可以移动正方形,使其在左边缘和下边缘具有点。我们将遍历正方形左边缘和下边缘的所有组合。 然后我们需要找到正方形的上边缘或右边缘。对于每一点,我们都可以确定它位于什么边缘。例如,如果
point.x-left>point.y-bottom
,则该点将位于正方形的右边缘,生成的区域将是(point.x-left)^2
。我们需要按正方形的面积对点进行排序:area=(max(point.x-left,point.y-bottom))^2
并从该排序列表中选择K
-第个点。它将是最小的正方形,至少包含K
个点和指定的左下角。这个解决方案的复杂性是O(n^3)
,这不是很好,但它比迭代K
点的所有组合要快。我的java解决方案:静态void initBounds(int[]x,int[]y)
{
minX=x[0];
maxX=x[0];
minY=y[0];
maxY=y[0];
对于(int i=1;imaxX)
maxX=x[i];
if(x[i]maxY)
maxY=y[i];
if(y[i]sx1&&x[i]sy1&&y[i]yDiff){
sx2=maxX+1;
sy2=最大值+侧差;
}否则{
sx2=最大x+侧差;
sy2=maxY+1;
}
面积=(sx2-sx1)*(sx2-sx1);
int p,q,r,s;
int minSize=(int)Math.sqrt(k)+1;
对于(p=sx1;p=minSize;i--){
int count=计算封闭点(x,y,p,q,p+i,q+i);
如果(计数>=k){
长面积=i*i;
if(电流面积<面积)
面积=面积;
}
其他的
打破
}
}
}
返回区;
}
生成所有可能的正方形,其面积(sqrt(k))*(sqrt(k))为所有点的最大边界正方形。正方形的左下角点可以位于边界正方形内的任何位置。考虑了至少容纳k个点所需的最小尺寸平方(sqrt(k))等约束。如果一个正方形包含至少k个点,且面积小于当前最小面积,则更新面积。看起来Michiel Smid有一篇关于此问题的论文: 提出了一种算法,在平面上给定一组n个点,然后 整数k,2≤ K≤ n、 查找最小封闭轴平行的k点 广场该算法的运行时间为O(n logn+kn log2) k) 并使用O(n) 空间以前解决这个问题最著名的算法是O(k 2n(对数n) 时间和使用O(kn)空间
你可以采取一种统计方法,计算x轴和y轴上每个点的标准偏差,然后去除第一个标准偏差最高的N-K点。你需要找到包含至少
K
点的正方形还是确切地说K
点的正方形?我真的不记得这个问题了,但至少应该是这样。也会改变这个问题。
static void initBounds(int[] x, int[] y)
{
minX = x[0];
maxX = x[0];
minY = y[0];
maxY = y[0];
for(int i = 1; i < x.length; i++){
if(x[i] > maxX)
maxX = x[i];
if(x[i] < minX)
minX = x[i];
if(y[i] > maxY)
maxY = y[i];
if(y[i] < minY)
minY = y[i];
}
}
static int countEnclosingPoints(int[] x, int[] y, int sx1, int sy1, int sx2, int sy2)
{
int count = 0;
for(int i = 0; i < x.length; i++)
{
if(x[i] > sx1 && x[i] < sx2 && y[i] > sy1 && y[i] < sy2)
count++;
}
return count;
}
static int minX;
static int minY;
static int maxX;
static int maxY;
static long minarea(int[] x, int[] y, int k) {
long area = 0;
initBounds(x, y);
int xDiff = maxX - minX;
int yDiff = maxY - minY;
int sx1 = minX - 1;
int sy1 = minY - 1;
int sideDiff = Math.abs(xDiff - yDiff) + 1;
int sx2;
int sy2;
if(xDiff > yDiff){
sx2 = maxX + 1;
sy2 = maxY + sideDiff;
} else {
sx2 = maxX + sideDiff;
sy2 = maxY + 1;
}
area = (sx2 - sx1) * (sx2 - sx1);
int p, q, r, s;
int minSize = (int) Math.sqrt(k) + 1;
for(p = sx1; p < sx2 - minSize; p++) {
for(q = sy1; q < sy2 - minSize; q++) {
int xd = sx2 - p; int yd = sy2 - q;
int sd = (xd < yd)? xd : yd;
for(int i = sd; i >= minSize; i--){
int count = countEnclosingPoints(x, y, p, q, p + i, q + i);
if(count >= k) {
long currArea = i * i;
if(currArea < area)
area = currArea;
}
else
break;
}
}
}
return area;
}