Java 从O(n^3)到O(n^2)的优化算法
我试图解决的问题如下: 假设在二维空间中有一组点,如何 我们能得到最大数量的共线点吗 我用Java解决了这个问题。 首先,我创建了一种检查线性的方法:Java 从O(n^3)到O(n^2)的优化算法,java,algorithm,optimization,Java,Algorithm,Optimization,我试图解决的问题如下: 假设在二维空间中有一组点,如何 我们能得到最大数量的共线点吗 我用Java解决了这个问题。 首先,我创建了一种检查线性的方法: return (y1 - y2) * (x1 - x3) = (y1 - y3) * (x1 - x2); 然后我使用了三个循环,这使得我的算法是O(n^3)。但我想看看这是否可以简化为O(n^2) 在网上搜索后,我发现我的实现与whats非常相似。所以问题是我们如何提高复杂性。任何例子都很好 这就是我最后做的: int p = 2; for
return (y1 - y2) * (x1 - x3) = (y1 - y3) * (x1 - x2);
然后我使用了三个循环,这使得我的算法是O(n^3)。但我想看看这是否可以简化为O(n^2)
在网上搜索后,我发现我的实现与whats非常相似。所以问题是我们如何提高复杂性。任何例子都很好
这就是我最后做的:
int p = 2;
for (int i = 0; i < points.lenght(); i++) {
for (int j = i+1; j < points.length(); j++) {
int count = 2;
for (int k =0; i < points.length(); k++) {
if (k == i || k == j)
continue;
//use linearity function to check if they are linear...
}
p = max(p,count);
}
}
int p=2;
对于(int i=0;i
您可以使用Ox使用两点之间的角度系数来解决此问题。例如,对于3个点:A B C。如果它们共线,当且仅当AB线和AC线与Ox线具有相同的角系数。这是我的伪代码:
// Type : an object to store information to use later
List<Type> res = new ArrayList<Type>();
for (int i = 0; i < points.lenght(); i++) {
for (int j = i+1; j < points.length(); j++) {
double coefficient = CoeffiecientBetweenTwoLine(
line(points[i], points[j]), line((0,0), (0,1));
res.add(new Type(points[i], points[j], coefficient);
}
}
//键入:用于存储信息以供以后使用的对象
List res=new ArrayList();
对于(int i=0;i
然后,使用快速排序,根据系数在列表上方再次排序。任何系数等于,我们就可以知道哪些点是共线的。该算法的复杂性是O(N^2logN)
(主要是用O(N^2)
元素对列表进行排序,构建列表只需要O(N^2)
)
@编辑:
那么,当我们显示等系数时,我们怎么知道有多少点共线呢?
有很多方法可以解决这个问题
- 在排序步骤中,您可以按第一个参数进行排序(即
当两个系数相等时。例如,排序后,
结果应为(在这种情况下,如果1 3和4共线):
(1 3)
(1 4)
(3 4)
从上面的建筑,你只需要看到条纹1。在这个例子中,是2。所以结果应该是3。(总是k+1)
- 使用公式:因为始终等于的对数:
n*(n-1)/2
。因此,您将有:n*(n-1)/2=3
。您可以知道n=3(n>=
这意味着你可以在这里解二次方程(但不能太多)
困难,因为你总是知道它有解决的办法,只是得到解决
一个解决方案(积极的)
编辑2
上面的步骤是为了知道有多少共线点是不正确的,因为在例如情况下,A B和C D是两条平行线(并且AB线不同于CD线),结果,它们仍然与Ox具有相同的系数。因此,我认为要解决此问题,可以使用联合查找
数据结构来解决此问题。步骤为:
角系数再排序
例如:(1,2,3,4)是共线的,它们与(5,6,7)平行,点8代表其他地方。因此,排序后,结果应该是:
(12)(13)(14)(23)(24)(56)(5,7)(6,7)角系数相等,但在两条不同的直线上
(1,5)(1,6)//将在两组平行线之间进行一些成对连接。(1,8)
(5,8)(3,8)..//随机顺序。因为我不知道
使用Union Find数据结构连接树:从第二个元素开始迭代,如果看到它的角度系数等于previous,则连接自身并连接previous。例如
(1,3)==(1,2):连接1和2,连接1和3
(1,4)==(1,3):连接1和3,连接1和4
(5,6):连接2和4,连接5和6
(5,7):加入5和7,加入5和6
(1,8):不加入任何东西。(5,8):不加入任何东西
完成这一步后,你所拥有的就是一棵多树,在每棵树中,都有一组共线的点
在上面的步骤中,您可以看到一些对是多次连接的。您可以简单地通过标记来解决这个问题,如果它们已经连接,请忽略以进一步提高性能
@:我认为这个解决方案不好,我只是凭我的大脑思考,而不是背后的真正算法。所以,还有什么清晰的想法,请告诉我。我得出了与@hqt的解决方案非常相似的结论,并想详细说明他们遗漏的细节
如果此类元素的比率dx
与dy
比率(即斜率)相同,则此类元素的两个元素相等
static class Direction {
Direction(Point p, Point q) {
// handle anti-parallel via normalization
// by making (dx, dy) lexicographically non-negative
if (p.x > q.x) {
dx = p.x - q.x;
dy = p.y - q.y;
} else if (p.x < q.x) {
dx = q.x - p.x;
dy = q.y - p.y;
} else {
dx = 0;
dy = Math.abs(p.y - q.y);
}
}
public boolean equals(Object obj) {
if (obj==this) return true;
if (!(obj instanceof Direction)) return false;
final Direction other = (Direction) obj;
return dx * other.dy == other.dx * dy; // avoid division
}
public int hashCode() {
// pretty hacky, but round-off error is no problem here
return dy==0 ? 42 : Float.floatToIntBits((float) dx / dy);
}
private final int dx, dy;
}
静态类方向{
方向(点p、点q){
//通过规范化处理反并行
//通过使(dx,dy)按字典顺序非负
如果(p.x>q.x){
dx=p.x-q.x;
dy=p.y-q.y;
}否则如果(p.x
现在通过在所有对上循环(复杂度O(n*n)
)来填充番石榴的Multimap
。迭代所有键(即方向)并通过a处理列表。找到的分区是一组共线点对。如果有k
coll
//just to create random 15 points
Random random = new Random();
ArrayList<Point> points = new ArrayList<Point>();
for(int i = 0; i < 15; i++){
Point p = new Point(random.nextInt(3), random.nextInt(3));
System.out.println("added x = " + p.x + " y = " + p.y);
points.add(p);
}
//code to count max colinear points
int p = 0;
for(int i = 0; i < points.size() -1; i++){
int colinear_with_x = 1;
int colinear_with_y = 1;
for(int j = i + 1; j < points.size(); j++){
if(points.get(i).x == points.get(j).x){
colinear_with_x++;
}
if(points.get(i).y == points.get(j).y){
colinear_with_y++;
}
}
p = max(p,colinear_with_x,colinear_with_y);
}
map<key=(vector, point), value=quantity> pointsOnLine
maxPoints = 2
for i=1 to n
for j=i+1 to n
newKey = lineParametersFromPoints(point[i], point[j])
if pointsOnLine.contains(newKey)
pointsOnLine[key] += 1
if maxPoints < pointsOnLine[key]
maxPoints = pointsOnLine[key]
else
pointsOnLine.add(key)
pointsOnLine[key] = 2