335 Self Crossing

You are given an array x of n positive numbers. You start at point (0,0) and moves x[0] metres to the north, then x[1] metres to the west, x[2] metres to the south, x[3] metres to the east and so on. In other words, after each move your direction changes counter-clockwise.
Write a one-pass algorithm with O(1) extra space to determine, if your path crosses itself, or not.
Example 1:

Given x = [2, 1, 1, 2],
┌───┐
│   │
└───┼──>
    │
Return true (self crossing)

Example 2:

Given x = [1, 2, 3, 4],
┌──────┐
│      │
│
│
└────────────>
Return false (not self crossing)

Example 3:

Given x = [1, 1, 1, 1],
┌───┐
│   │
└───┼>
Return true (self crossing)

Solution

class Solution {
public:
    struct point {
        int x, y;
        point(int x0, int y0): x(x0), y(y0) {};
    };

    bool isCrossing(vector<point*> points, int a, int b, int c, int d){
        if ( a < 0 or b < 0 or c < 0 or d < 0 ) return false;
        point *l10 = points[a], *l11 = points[b], *l20 = points[c], *l21 = points[d];
        int x10 = l10->x, y10 = l10->y, x11 = l11->x, y11 = l11->y;
        int x20 = l20->x, y20 = l20->y, x21 = l21->x, y21 = l21->y;
        if ( x10 == x11 ) {
            return ( (x10-x20)*(x10-x21) <= 0 and ( (y20-y11)*(y20-y10) <= 0 or (y21-y11)*(y21-y10) <= 0 ) );
        }
        if ( y10 == y11 ) {
            return ( (y10-y20)*(y10-y21) <= 0 and ( (x20-x11)*(x20-x10) <= 0 or (x21-x11)*(x21-x10) <= 0 ) );
        }
        return false;
    }
    bool isSelfCrossing(vector<int>& x) {
        int n = x.size();
        if ( n <= 3 ) false;
        vector<point*> points;
        points.push_back(new point(0, 0));
        vector<pair<int, int>> e;
        e.push_back(pair<int, int>(0, 1));
        e.push_back(pair<int, int>(-1, 0));
        e.push_back(pair<int, int>(0, -1));
        e.push_back(pair<int, int>(1, 0));
        int x0 = 0, y0 = 0, np;
        for ( int i = 0; i < n; i++ ) {
            x0 += e[i%4].first * x[i];
            y0 += e[i%4].second * x[i];
            points.push_back(new point(x0, y0));
            if ( int(points.size()) == 8 ) points.erase(points.begin());
            np = points.size();
            if ( isCrossing(points, np-1, np-2, np-4, np-5) ) return true;
            if ( isCrossing(points, np-1, np-2, np-5, np-6) ) return true;
            if ( isCrossing(points, np-1, np-2, np-6, np-7) ) return true;
        }
        return false;
    }
};

Notes
关键是提取出“可能相交”的三种情况,除了题干中给的example1和example3, 还可能有以下这种情况:

   x(1)
    ┌──────┐
    │      │x(0)
x(2)│     <│────│
    │       x(5)│x(4)
    └───────────│

这三种情况分别对应:

  • 第i条线段和第(i-3)条线段相交;
  • 第i条线段和第(i-4)条线段相交;
  • 第i条线段和第(i-5)条线段相交。 只需要对这三组线段的相交情况进行判断即可。

results matching ""

    No results matching ""