路径交叉,有点难度

Posted Roam-G

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了路径交叉,有点难度相关的知识,希望对你有一定的参考价值。

335. 路径交叉

难度困难104

给你一个整数数组 distance 

从 X-Y 平面上的点 (0,0) 开始,先向北移动 distance[0] 米,然后向西移动 distance[1] 米,向南移动 distance[2] 米,向东移动 distance[3] 米,持续移动。也就是说,每次移动后你的方位会发生逆时针变化。

判断你所经过的路径是否相交。如果相交,返回 true ;否则,返回 false 。

示例 1:

输入:distance = [2,1,1,2]
输出:true

示例 2:

输入:distance = [1,2,3,4]
输出:false

示例 3:

输入:distance = [1,1,1,1]
输出:true

提示:

  • 1 <= distance.length <= 105
  • 1 <= distance[i] <= 105

通过次数8,755提交次数21,108

我们先通过枚举各种移动方案来归纳路径交叉的规律。

第 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。

至此,我们已经通过归纳基本得到了路径交叉的规律。

方法一:归纳法(归纳路径交叉的情况)
思路和算法

根据归纳结果,我们发现所有可能的路径交叉的情况只有以下三类:

第 11 类,如上图所示,第 ii 次移动和第 i-3i−3 次移动(包含端点)交叉的情况,例如归纳中的 4-24−2、4-34−3、4-54−5 和 4-64−6。

这种路径交叉需满足以下条件:

第 i-1i−1 次移动距离小于等于第 i-3i−3 次移动距离。
第 ii 次移动距离大于等于第 i-2i−2 次移动距离。


第 22 类,如上图所示,第 55 次移动和第 11 次移动交叉(重叠)的情况,例如归纳中的 5-25−2 和 5-35−3。这类路径交叉的情况实际上是第 33 类路径交叉在边界条件下的一种特殊情况。

这种路径交叉需要满足以下条件:

第 44 次移动距离等于第 22 次移动距离。
第 55 次移动距离大于等于第 33 次移动距离减第 11 次移动距离的差;注意此时第 33 次移动距离一定大于第 11 次移动距离,否则在上一步就已经出现第 11 类路径交叉的情况了。


第 33 类,如上图所示,第 ii 次移动和第 i-5i−5 次移动(包含端点)交叉的情况,例如归纳中的 6-26−2 和 6-36−3。

这种路径交叉需满足以下条件:

第 i-1i−1 次移动距离大于等于第 i-3i−3 次移动距离减第 i-5i−5 次移动距离的差,且小于等于第 i-3i−3 次移动距离;注意此时第 i-3i−3 次移动距离一定大于第 i-5i−5 次移动距离,否则在两步之前就已经出现第 11 类路径交叉的情况了。
第 i-2i−2 次移动距离大于第 i-4i−4 次移动距离;注意此时第 i-2i−2 次移动距离一定不等于第 i-4i−4 次移动距离,否则在上一步就会出现第 33 类路径交叉(或第 22 类路径交叉)的情况了。
第 ii 次移动距离大于等于第 i-2i−2 次移动距离减第 i-4i−4 次移动距离的差。

class Solution {
public:
    bool isSelfCrossing(vector<int>& distance) {
        int n = distance.size();
        for (int i = 3; i < n; ++i) {
            // 第 1 类路径交叉的情况
            if (distance[i] >= distance[i - 2] && distance[i - 1] <= distance[i - 3]) {
                return true;
            }

            // 第 2 类路径交叉的情况
            if (i == 4 && (distance[3] == distance[1]
                && distance[4] >= distance[2] - distance[0])) {
                return true;
            }

            // 第 3 类路径交叉的情况
            if (i >= 5 && (distance[i - 3] - distance[i - 5] <= distance[i - 1]
                && distance[i - 1] <= distance[i - 3]
                && distance[i] >= distance[i - 2] - distance[i - 4]
                && distance[i - 2] > distance[i - 4])) {
                return true;
            }
        }
        return false;
    }
};

java

class Solution {
    public boolean isSelfCrossing(int[] distance) {
        int n = distance.length;
        for (int i = 3; i < n; ++i) {
            // 第 1 类路径交叉的情况
            if (distance[i] >= distance[i - 2] && distance[i - 1] <= distance[i - 3]) {
                return true;
            }

            // 第 2 类路径交叉的情况
            if (i == 4 && (distance[3] == distance[1]
                && distance[4] >= distance[2] - distance[0])) {
                return true;
            }

            // 第 3 类路径交叉的情况
            if (i >= 5 && (distance[i - 3] - distance[i - 5] <= distance[i - 1]
                && distance[i - 1] <= distance[i - 3]
                && distance[i] >= distance[i - 2] - distance[i - 4]
                && distance[i - 2] > distance[i - 4])) {
                return true;
            }
        }
        return false;
    }
}

Python

class Solution:
    def isSelfCrossing(self, distance: List[int]) -> bool:
        n = len(distance)
        for i in range(3, n):
            # 第 1 类路径交叉的情况
            if (distance[i] >= distance[i - 2]
                    and distance[i - 1] <= distance[i - 3]):
                return True

            # 第 2 类路径交叉的情况
            if i == 4 and (distance[3] == distance[1]
                           and distance[4] >= distance[2] - distance[0]):
                return True

            # 第 3 类路径交叉的情况
            if i >= 5 and (distance[i - 3] - distance[i - 5] <= distance[i - 1] <= distance[i - 3]
                           and distance[i] >= distance[i - 2] - distance[i - 4]
                           and distance[i - 2] > distance[i - 4]):
                return True
        return False

以上是关于路径交叉,有点难度的主要内容,如果未能解决你的问题,请参考以下文章

c_cpp 349.两个阵列的交叉点 - 难度易 - 2018.9.17

有点难度Vue 面试题+详解答案

简化路径中等难度

简化路径中等难度

iOS xcode 代码片段

C++ 代码片段(积累)