Count Number of Triples in an array that are collinear

后端 未结 6 788
梦谈多话
梦谈多话 2021-02-01 09:31

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

Given an array say Arr[N] containing Cartesian coordinates of N distinct points count the

6条回答
  •  梦谈多话
    2021-02-01 09:57

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

    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
    

    or to

    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
    

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

    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 
    #include 
    #include 
    #include 
    
    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 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 CollinearPoints;
        typedef std::map 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;
    }
    

提交回复
热议问题