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)
Tips:
题目中对额外的使用空间进行了限制,
这里不加证明的给出:若按顺序给各条线段编号,有线段相交,则必有相交线段的编号差值不超过6,(即若线段8为最后一条线段且发生了相交,则相交的线段编号必大于2,这一点我证明不出来,可以自己画一下,不可能有差值超过6的情况,实际上,编号为n的线段只可能与编号为n-3,n-4,n-5的线段相交,n-i>0,后面会用到)。
这样的话,只需要保存后7个点的信息,具体算法为:
1)计算各点的坐标,并保存后7个点;
2)计算线段 n 和 n-i 的端点信息;
3)判断两线段是否相交;
4)重复步骤1)2) 3),直到返回true或输入结束。
判断两线段是否相交的方法:
1)两线段交叉:线段1的两端点记为l11和l12,同理线段2的两端点记为l21和l22,计算l11和l21横坐标的差值及l12和l22横坐标的差值,想乘记为dif1,同理计算纵坐标的差值记为dif2,若dif1和dif2均小于0,则相交;
2)最后一线段的末端点在另一线段上(不共端点):dif1和dif2其中一个小于0,另一个等于0;
3)共端点:直接判断是否有端点相同。
bool isSelfCrossing(vector<int>& x) {
int pos[7][2]; //记录7个点的坐标
int line[2][2][2]; //待判断的两条线的端点坐标
memset(pos, 0, sizeof(pos));
int NS = 0, EW = 0; //坐标
int cnt = 0, k;
int posi = 0;
for (auto &a : x){ //计算坐标
k = cnt % 4;
switch (k){
case 0:
NS += a;
break;
case 1:
EW -= a;
break;
case 2:
NS -= a;
break;
case 3:
EW += a;
break;
}
++cnt;
posi = cnt % 7;
pos[posi][0] = EW;
pos[posi][1] = NS;
int tmp, m = 0;
int dif1, dif2;
if (cnt == 4) m = 3;
else if (cnt == 5) m = 4;
else if (cnt >= 6) m = 5;
for (int i = 3; i <= m; ++i){ //找出待判断的两条线并判断
tmp = posi;
line[0][0][0] = pos[tmp][0];
line[0][0][1] = pos[tmp][1];
tmp = (posi + 6) % 7;
line[0][1][0] = pos[tmp][0];
line[0][1][1] = pos[tmp][1];
tmp = (posi + 7 - i) % 7;
line[1][0][0] = pos[tmp][0];
line[1][0][1] = pos[tmp][1];
tmp = (posi + 6 - i) % 7;
line[1][1][0] = pos[tmp][0];
line[1][1][1] = pos[tmp][1];
dif1 = (line[0][0][0] - line[1][0][0])*(line[0][1][0] - line[1][1][0]);
dif2 = (line[0][0][1] - line[1][0][1])*(line[0][1][1] - line[1][1][1]);
if ((dif1 < 0 && dif2 < 0) || (dif1 == 0 && dif2 < 0) || (dif1 < 0 && dif2 == 0) ||
(line[0][0][0] == line[1][1][0] && line[0][0][1] == line[1][1][1]))
return true;
}
}
return false;
}