计算共线数组中的三元组数 [英] Count Number of Triples in an array that are collinear

查看:209
本文介绍了计算共线数组中的三元组数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人问我这个面试问题(C ++,算法),却不知道如何解决。

I was asked this Interview Question (C++,algos)and had no idea how to solve it.

给出一个数组,说Arr [N]包含笛卡尔坐标N个不同的点计数三元组的数目(Arr [P],Arr [Q],Arr [R]),使得P <0。 Q < R < N和点Arr [P],Arr [Q],Arr [R]是共线的(即位于同一条直线上)。

Given an array say Arr[N] containing Cartesian coordinates of N distinct points count the number of triples (Arr[P], Arr[Q], Arr[R]) such that P < Q < R < N and the points Arr[P], Arr[Q], Arr[R] are collinear (i.e lie on the same straight line).

有什么想法吗?我可以为此使用哪种算法?

Any ideas? What algorithm can I use for this?

推荐答案

以下内容可能未经过优化,但其复杂性正是您的面试官所要求的。

The following is probably not optimized, but its complexity is the one your interviewer requested.

首先为每个点(N²复杂度)创建一个(a,b,c)值列表
->(a,b,c )代表直线的笛卡尔方程a * x + b * y + c = 0
给定两个点及其坐标(xa,ya)和(xb,yb),计算(a,b,c )很简单。
您可以找到

First create a list of (a,b,c) values for each couple of points (N² complexity) --> (a,b,c) stands for the cartesian equation of a straight line a*x+b*y+c=0 Given two points and their coordinates (xa, ya) and (xb, yb), computing (a,b,c) is simple. Either you can find a solution to

ya=alpha*xa+beta  
yb=alpha*xb+beta

(if (xb-xa) != 0)
alpha = (yb-ya)/(xb-xa)
beta = ya - alpha*xa
a = alpha
b = -1
c = beta

xa = gamma*ya+delta
xb = gamma*yb+delta
(you get the point)

然后可以用更通用的形式重写可解方程组

The solvable set of equations can then be rewritten in the more general form

a*x+b*y+c = 0

然后对列表排序(N²log(N²)复杂度,因此N²log(N)复杂度)。

Then sort the list (N² log(N²) complexity therefore N²log(N) complexity).

迭代列表的元素。如果两个顺序元素相等,则对应的点是共线的。 N²复杂度。

Iterate over elements of the list. If two sequential elements are equal, corresponding points are collinear. N² complexity.

您可能想添加最后一个操作以过滤重复的结果,但是在复杂度方面应该没问题。

You might want to add a last operation to filter duplicate results, but you should be fine, complexity-wise.

编辑:我在编码时对算法进行了一些更新,使其更简单,更优化。

EDIT : i updated a bit the algorithm while coding it to make it more simple and optimal. Here it goes.

#include <map>
#include <set>
#include <vector>
#include <iostream>

struct StraightLine
{
    double a,b,c;
    StraightLine() : a(0.),b(0.),c(0.){}
    bool isValid() { return a!=0. || b!= 0.; }
    bool operator<(StraightLine const& other) const
    {
        if( a < other.a ) return true;
        if( a > other.a ) return false;
        if( b < other.b ) return true;
        if( b > other.b ) return false;
        if( c < other.c ) return true;
        return false;
    }
};

struct Point { 
    double x, y; 
    Point() : x(0.), y(0.){}
    Point(double p_x, double p_y) : x(p_x), y(p_y){}
};

StraightLine computeLine(Point const& p1, Point const& p2)
{
    StraightLine line;
    if( p2.x-p1.x != 0.)
    {
        line.b = -1;
        line.a = (p2.y - p1.y)/(p2.x - p1.x);
    }
    else if( p2.y - p1.y != 0. )
    {
        line.a = -1;
        line.b = (p2.x-p1.x)/(p2.y-p1.y);
    }
    line.c = - line.a * p1.x - line.b * p1.y;
    return line;
}

int main()
{
    std::vector<Point> points(9);
    for( int i = 0 ; i < 3 ; ++i )
    {
        for( int j = 0; j < 3 ; ++j )
        {
            points[i*3+j] = Point((double)i, (double)j);
        }
    }


    size_t nbPoints = points.size();
    typedef std::set<size_t> CollinearPoints;
    typedef std::map<StraightLine, CollinearPoints> Result;
    Result result;

    for( int i = 0 ; i < nbPoints ; ++i )
    {
        for( int j = i + 1 ; j < nbPoints ; ++j )
        {
            StraightLine line = computeLine(points[i], points[j]);
            if( line.isValid() )
            {
                result[line].insert(i);
                result[line].insert(j);
            }
        }
    }

    for( Result::iterator currentLine = result.begin() ; currentLine != result.end(); ++currentLine )
    {
        if( currentLine->second.size() <= 2 )
        {
            continue;
        }
        std::cout << "Line";
        for( CollinearPoints::iterator currentPoint = currentLine->second.begin() ; currentPoint != currentLine->second.end() ; ++currentPoint )
        {
            std::cout << " ( " << points[*currentPoint].x << ", " << points[*currentPoint].y << ")";
        }
        std::cout << std::endl;
    }
    return 0;
}

这篇关于计算共线数组中的三元组数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆