LeetCode每日一题(335. Self Crossing)

You are given an array of integers distance.

You start at point (0,0) on an X-Y plane and you move distance[0] meters to the north, then distance[1] meters to the west, distance[2] meters to the south, distance[3] meters to the east, and so on. In other words, after each move, your direction changes counter-clockwise.

Return true if your path crosses itself, and false if it does not.

Example 1:

Input: distance = [2,1,1,2]
Output: true

Example 2:

Input: distance = [1,2,3,4]
Output: false

Example 3:

Input: distance = [1,1,1,1]
Output: true

Constraints:

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

整体趋势分成两种, 一种是扩大, 即旋转半径持续增大, 一种是收缩, 即旋转半径减小, 如果是一直保持扩大的趋势,那就不会出现交叉的情况。一旦出现收缩的趋势就不可能恢复成扩大,半径一定会持续缩小下去,直到完成最后一步,或者中途出现交叉。 我们把上下左右分别确立边界,不管趋势是放大还是收缩,每走一步都会更新一个边界, 具体来说,是向上走的时候更新下边界,向左走的时候更新右边界, 向下走的时候更新上边界, 向右走的时候更新左边界, 边界的更新整体比移动慢一步, 这样是为了保证我们在判断下一步是否会与边界发生交叉的时候不会出现误判。判断交叉的时候,因为最小距离为 1, 所以除了对边不检查之外, 剩下的三个边界都需要进行检查,即向上走的时候不检查左边界, 向左走的时候不检查下边界, 向下走的时候不检查右边界, 向右走的时候不检查上边界.



impl Solution {
    fn next_point(curr: (i32, i32), dir: &str, distance: i32) -> (i32, i32) {
        match dir {
            "up" => return (curr.0, curr.1 + distance),
            "left" => return (curr.0 - distance, curr.1),
            "down" => return (curr.0, curr.1 - distance),
            "right" => return (curr.0 + distance, curr.1),
            _ => unreachable!(),
        }
    }

    fn is_crossing(a_start: (i32, i32), a_end: (i32, i32), b_start: (i32, i32), b_end: (i32, i32)) -> bool {
        let a_dir = if a_start.0 == a_end.0 { "vertical" } else { "horizontal" };
        let b_dir = if b_start.0 == b_end.0 { "vertical" } else { "horizontal" };
        if a_dir == b_dir {
            if a_dir == "vertical" {
                if a_start.0 != b_start.0 {
                    return false;
                }
                let a_min_y = a_start.1.min(a_end.1);
                let a_max_y = a_start.1.max(a_end.1);
                let b_min_y = b_start.1.min(b_end.1);
                let b_max_y = b_start.1.max(b_end.1);
                return !(a_max_y < b_min_y || a_min_y > b_max_y);
            }
            if a_start.1 != b_start.1 {
                return false;
            }
            let a_min_x = a_start.0.min(a_end.0);
            let a_max_x = a_start.0.max(a_end.0);
            let b_min_x = b_start.0.min(b_end.0);
            let b_max_x = b_start.0.max(b_end.0);
            return !(a_max_x < b_min_x || a_min_x > b_max_x);
        }
        if a_dir == "vertical" {
            let a_min_y = a_start.1.min(a_end.1);
            let a_max_y = a_start.1.max(a_end.1);
            let b_min_x = b_start.0.min(b_end.0);
            let b_max_x = b_start.0.max(b_end.0);
            return a_min_y <= b_start.1 && a_max_y >= b_start.1 && b_min_x <= a_start.0 && b_max_x >= a_start.0;
        }

        let a_min_x = a_start.0.min(a_end.0);
        let a_max_x = a_start.0.max(a_end.0);
        let b_min_y = b_start.1.min(b_end.1);
        let b_max_y = b_start.1.max(b_end.1);
        return a_min_x <= b_start.0 && a_max_x >= b_start.0 && b_min_y <= a_start.1 && b_max_y >= a_start.1;
    }

    pub fn is_self_crossing(distance: Vec<i32>) -> bool {
        let dirs = vec!["up", "left", "down", "right"];
        let mut left_border = (0, 0, 0, 0);
        let mut right_border = (0, 0, 0, 0);
        let mut top_border = (0, 0, 0, 0);
        let mut bottom_border = (0, 0, 0, 0);
        let mut points = vec![(0, 0)];
        let mut trend = "expanding";
        for i in 0..distance.len() {
            let (next_x, next_y) = Solution::next_point(points[i], &dirs[i % 4], distance[i]);
            if trend == "shrinking" {
                let start = (points[i].0, points[i].1);
                let end = (next_x, next_y);
                let left_start = (left_border.0, left_border.1);
                let left_end = (left_border.2, left_border.3);
                let right_start = (right_border.0, right_border.1);
                let right_end = (right_border.2, right_border.3);
                let top_start = (top_border.0, top_border.1);
                let top_end = (top_border.2, top_border.3);
                let bottom_start = (bottom_border.0, bottom_border.1);
                let bottom_end = (bottom_border.2, bottom_border.3);
                match dirs[i % 4].clone() {
                    "up" => {
                        let mut is_crossing = false;
                        is_crossing |= Solution::is_crossing(right_start, right_end, start, end);
                        is_crossing |= Solution::is_crossing(bottom_start, bottom_end, start, end);
                        is_crossing |= Solution::is_crossing(top_start, top_end, start, end);
                        if is_crossing {
                            return true;
                        }
                    }
                    "left" => {
                        let mut is_crossing = false;
                        is_crossing |= Solution::is_crossing(left_start, left_end, start, end);
                        is_crossing |= Solution::is_crossing(right_start, right_end, start, end);
                        is_crossing |= Solution::is_crossing(top_start, top_end, start, end);
                        if is_crossing {
                            return true;
                        }
                    }
                    "down" => {
                        let mut is_crossing = false;
                        is_crossing |= Solution::is_crossing(left_start, left_end, start, end);
                        is_crossing |= Solution::is_crossing(bottom_start, bottom_end, start, end);
                        is_crossing |= Solution::is_crossing(top_start, top_end, start, end);
                        if is_crossing {
                            return true;
                        }
                    }
                    "right" => {
                        let mut is_crossing = false;
                        is_crossing |= Solution::is_crossing(left_start, left_end, start, end);
                        is_crossing |= Solution::is_crossing(bottom_start, bottom_end, start, end);
                        is_crossing |= Solution::is_crossing(right_start, right_end, start, end);
                        if is_crossing {
                            return true;
                        }
                    }
                    _ => unreachable!(),
                }
            }
            match dirs[i % 4].clone() {
                "up" => {
                    if next_y <= top_border.1 {
                        trend = "shrinking";
                    }
                    if i > 0 {
                        bottom_border = (points[i - 1].0, points[i - 1].1, points[i].0, points[i].1);
                    }
                }
                "left" => {
                    if next_x >= left_border.0 {
                        trend = "shrinking";
                    }
                    right_border = (points[i - 1].0, points[i - 1].1, points[i].0, points[i].1);
                }
                "down" => {
                    if next_y >= bottom_border.1 {
                        trend = "shrinking";
                    }
                    top_border = (points[i - 1].0, points[i - 1].1, points[i].0, points[i].1);
                }
                "right" => {
                    if next_x <= right_border.0 {
                        trend = "shrinking";
                    }
                    left_border = (points[i - 1].0, points[i - 1].1, points[i].0, points[i].1);
                }
                _ => unreachable!(),
            }
            points.push((next_x, next_y));
        }
        false
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值