路径交叉
问题描述:
给你一个整数数组 distance 。
从 X-Y 平面上的点 (0,0) 开始,先向北移动 distance[0] 米,然后向西移动 distance[1] 米,向南移动 distance[2] 米,向东移动 distance[3] 米,持续移动。也就是说,每次移动后你的方位会发生逆时针变化。
判断你所经过的路径是否相交。如果相交,返回 true ;否则,返回 false 。
解题思路:
1、不管拐多少个弯,不相交的形状最多有两种形状:由内到外、由外到内的螺旋,且一定是向外->向内,向外时判断边界条件,在未超出前边界时转为向内螺旋;根据不同情况确定向内时的边界,超出则说明相交。由于初始没有图形,可以先走几步形成基本轮廓,简化边界条件计算。
2、走完三步时一定不会相交,走完三步时如果在二象限或x轴,则一定开始向内螺旋;如果在第三象限,第四步一定不会相交。走完第四步时,如果在三象限或y轴,则一定开始向内螺旋;如果在四象限,则可以继续向外螺旋。走完4步时,基本外螺旋轮廓已经形成。
3、继续走剩下的,若某一步未超出上一圈的边界,转为向内螺旋计算(这里要注意,以向上走为例,未超出上边界和未到达下边界时形状不同!)
问题求解:
struct pair_hash {
template <class T1, class T2>
std::size_t operator()(const std::pair<T1, T2>& p) const {
auto h1 = std::hash<T1>{}(p.first);
auto h2 = std::hash<T2>{}(p.second);
return h1 ^ h2;
}
};
class Solution {
public:
bool isSelfCrossing(vector<int>& distance) {
unordered_map<pair<int, int>, int, pair_hash> mp;
int x = 0, y = 0;
mp[make_pair(0, 0)]++;
int n = distance.size();
for (int i = 0; i < n - 1; i++) {
if (distance[i] < distance[i + 1]) {
if (i == n - 3) return false;
} else break;
}
for (int i = 0; i < n; i++) {
if (i % 4 == 0)
while (distance[i]-- || distance[i] == 0)
if (!mp[make_pair(x, y + 1)]) mp[make_pair(x, ++y)]++;
else return true;
else if (i % 4 == 1)
while (distance[i]-- || distance[i] == 0)
if (!mp[make_pair(x - 1, y)]) mp[make_pair(--x, y)]++;
else return true;
else if (i % 4 == 2)
while (distance[i]-- || distance[i] == 0)
if (!mp[make_pair(x, y - 1)]) mp[make_pair(x, --y)]++;
else return true;
else
while (distance[i]-- || distance[i] == 0)
if (!mp[make_pair(x + 1, y)]) mp[make_pair(++x, y)]++;
else return true;
}
return false;
}
};
问题总结:
先看一下leetcode官方的解释:
我们先通过枚举各种移动方案来归纳路径交叉的规律。
第 11 次移动和第 22 次移动的情况:
因为这两次移动都是各自方向上的第一次移动,所以这两次移动距离将作为之后移动距离的参考系,但本身没有意义。因此,此时只有 2-12−1 一种情况。
第 33 次移动的情况:
此时一定是 2-12−1,第 33 次移动距离相较于第 11 次移动距离,有三种情况:
3-13−1:第 33 次移动距离小于第 11 次移动距离;
3-23−2:第 33 次移动距离等于第 11 次移动距离;
3-33−3:第 33 次移动距离大于第 11 次移动距离。
第 44 次移动的情况:
当前 33 次移动是 3-13−1 时,第 44 次移动距离相较于第 22 次移动距离,有两种情况:
4-14−1:第 44 次移动距离小于第 22 次移动距离;
4-24−2 和 4-34−3:第 44 次移动距离大于等于第 22 次移动距离相同,出现路径交叉。
根据以上结果,我们发现 3-13−1 具有如下性质:如果在当前的第 ii 次移动之后,存在第 jj 次移动(j > ij>i)的距离大于等于第 j-2j−2 次移动的距离,则会出现路径交叉。另外,我们发现 4-14−1 具有和 3-13−1 相同的性质,于是 4-14−1 等价于 3-13−1;不需要继续讨论 4-14−1 的后续情况。
当前 33 次移动是 3-23−2 时,第 44 次移动距离相较于第 22 次移动距离,有两种情况:
4-44−4:第 44 次移动距离小于第 22 次移动距离;
4-54−5 和 4-64−6:第 44 次移动距离大于等于第 22 次移动距离,出现路径交叉。
根据以上结果,我们发现 3-23−2 具有和 3-13−1 相同的性质,于是 4-44−4 等价于 3-23−2,并间接地等价于 3-13−1;不需要继续讨论 4-44−4 的后续情况。
当前 33 次移动是 3-33−3 时,第 44 次移动距离相较于第 22 次移动距离,有三种情况:
4-74−7:第 44 次移动距离小于第 22 次移动距离;
4-84−8:第 44 次移动距离等于第 22 次移动距离;
4-94−9:第 44 次移动距离大于第 22 次移动距离。
根据以上结果,我们发现 4-74−7 也具有和 3-13−1 相同的性质,于是 4-74−7 等价于 3-13−1;不需要继续讨论 4-74−7 的后续情况。
第 55 次移动的情况:
此时还需要讨论前 44 次移动是 4-84−8 或 4-94−9 的情况。
当前 44 次移动是 4-84−8 时,第 55 次移动距离相较于第 33 次移动距离和第 11 次移动距离,有两种情况:
5-15−1:第 55 次移动距离小于第 33 次移动距离减第 11 次移动距离的差;
5-25−2 和 5-35−3:第 55 次移动距离大于等于第 33 次移动距离减第 11 次移动距离的差,出现路径交叉。
根据以上结果,我们发现 5-15−1 也具有和 3-13−1 相同的性质,于是 5-15−1 等价于 3-13−1;不需要继续讨论 5-15−1 的后续情况。
当前 44 次移动是 4-94−9 时,第 55 次移动距离相较于第 33 次移动距离和第 11 次移动距离,有三种情况:
5-45−4:第 55 次移动距离小于第 33 次移动距离减第 11 次移动距离的差;
5-55−5、5-65−6 和 5-75−7:第 55 次移动距离大于等于第 33 次移动距离减第 11 次移动距离的差,且小于等于第 33 次移动距离;
5-85−8:第 55 次移动距离大于第 33 次移动距离。
根据以上结果,我们发现 5-45−4 也具有和 3-13−1 相同的性质,于是 5-15−1 等价于 3-13−1;不需要继续讨论 5-45−4 的后续情况。
第 66 次移动的情况:
此时还需要讨论前 55 次移动是 5-55−5、5-65−6 或 5-75−7 的情况,以及前 55 次移动是 5-85−8 的情况。
当前 55 次移动是 5-55−5、5-65−6 或 5-75−7 时,我们不妨以 5-65−6 为例,第 66 次移动距离相较于第 44 次移动距离和第 22 次移动距离,有两种情况:
6-16−1:第 66 次移动距离小于第 44 次移动距离减第 22 次移动距离的差;
6-26−2 和 6-36−3:第 66 次移动距离大于等于第 44 次移动距离减第 22 次移动距离的差,出现路径交叉。
根据以上结果,我们发现 6-16−1 也具有和 3-13−1 相同的性质,于是 6-16−1 等价于 3-13−1;不需要继续讨论 6-16−1 的后续情况。
当前 55 次移动是 5-85−8 时,第 66 次移动距离相较于第 44 次移动距离和第 22 次移动距离,有三种情况:
6-46−4:第 66 次移动距离小于第 44 次移动距离减第 22 次移动距离的差;
6-56−5、6-66−6 和 6-76−7:第 66 次移动距离大于等于第 44 次移动距离减第 22 次移动距离的差,且小于等于第 44 次移动距离;
6-86−8:第 66 次移动距离大于第 44 次移动距离。
根据以上结果,我们发现 6-46−4 与 5-45−4 的情况类似,都具有 3-13−1 的性质;6-56−5、6-66−6、6-76−7 与 5-55−5、5-65−6、5-75−7 的情况类似,后续可能出现的情况类似于 6-16−1、6-26−2 和 6-36−3;6-86−8 与 5-85−8 的情况类似,后续可能出现的情况类似 6-46−4、6-56−5、6-66−6、6-76−7 和 6-86−8。
至此,我们已经通过归纳基本得到了路径交叉的规律。
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/self-crossing/solution/lu-jing-jiao-cha-by-leetcode-solution-dekx/
来源:力扣(LeetCode)