题目描述:
给你一个整数数组 distance 。
从 X-Y 平面上的点 (0,0) 开始,先向北移动 distance[0] 米,然后向西移动 distance[1] 米,向南移动 distance[2] 米,向东移动 distance[3] 米,持续移动。也就是说,每次移动后你的方位会发生逆时针变化。
判断你所经过的路径是否相交。如果相交,返回 true ;否则,返回 false 。
方法一:
class Solution {
public:
bool isSelfCrossing(vector<int>& distance) {
//第一阶段,在图形逐渐扩大的过程中,每个图形都可以分为a、b、c、d四种边
int a = 0, b = 0, c = 0, d = 0;
int n = distance.size();
//第二阶段,在图形逐渐缩小的过程中,每个图形都可以分为x、y两种边
int x = 0, y = 0;
int index = n;
//开始第一阶段,图形逐渐扩大
for (int i = 0; i < n; i++)
{
int newlen = distance[i];
//若新的一条边仍然大于c,就说明还处于第一阶段
if (newlen > c)
{
a = b;
b = c;
c = d;
d = newlen;
}
//若新的一条边小于c - a,就判断是否路径交叉,若没有则即将进入第二阶段
else if (newlen < c - a)
{
//若存在下一条边,且其长度小于d,说明不会交叉,进入第二阶段
if (i + 1 < n && distance[i + 1] < d)
{
x = d;
y = newlen;
index = i + 1;
break;
}
//若存在下一条边,且其长度大于等于d,说明不会交叉,进入第二阶段
else if (i + 1 < n && distance[i + 1] >= d)
{
return true;
}
}
//若新的一条边大于等于c - a,小于等于c,就判断是否路径交叉,若没有则即将进入第二阶段
else if (newlen >= c - a && newlen <= c)
{
//若存在下一条边,且其长度小于d - b,说明不会交叉,进入第二阶段
if (i + 1 < n && distance[i + 1] < d - b)
{
x = d;
y = newlen;
index = i + 1;
break;
}
//若存在下一条边,且其长度大于等于d - b,说明不会交叉,进入第二阶段
else if (i + 1 < n && distance[i + 1] >= d - b)
{
return true;
}
}
}
//进入第二阶段,图形逐渐缩小
for (int i = index; i < n; i++)
{
int newlen = distance[i];
//若新的一条边小于x,说明不会路径交叉
if (newlen < x)
{
x = y;
y = newlen;
}
//若新的一条边大于x,则说明路径交叉了
else if (newlen >= x)
{
return true;
}
}
return false;
}
};
自己画了好多图,才找到的规律,最后一遍过。
我找出的规律是,若将走过的路径看成一个图形,那么这个图形可以分为两个阶段:第一个阶段图形不断扩大,第二个阶段图像将会不断缩小。什么意思呢?请看下文。
第一阶段
第一阶段的不断扩大,即是每次走的竖线都比前一条竖线更长,每次走的横线也都比前一条横线更长,因此能够保证不会有路径交叉。观察下图可以发现,每个图形都可以分出四种边:a, b, c, d,这说明只要处于第一阶段,不管什么样的图形都可以视为同一个模型,这对解题是很有帮助的。
我在每次遍历时,都将a,b,c,d四条边随图形变化,这样每次读取到的一条新的边newlen,只要判断其大小和c的关系:
①若newlen > c,那么将不会有路径交叉,图形依旧处于第一阶段,继续遍历。
②若newlen < c - a,那么注意将可能有路径交叉,如果newlen的下一条边大于等于d,就会出现路径交叉,否则就进入第二阶段。
③若newlen >= c - a && newlen <= c,如果newlen的下一条边大于等于d - b,就会出现路径交叉,否则就进入第二阶段。
第二阶段
第二阶段的图形,由于受到限制将会越来越小,即每次走的竖线应该比前一条竖线更短,每次走的横线应该比前一条横线更短。
如下图所示,可以看出,这三个图形以后的每一条边的长度,都应该小于x和y才行,否则就会出现路径交叉,同样,每次遍历时更新x和y的长度,毕竟x和y将会越来越小。