JAVA程序设计:游乐园的迷宫(LCP 15)

小王来到了游乐园,她玩的第一个项目是模拟推销员。有一个二维平面地图,其中散布着 N 个推销点,编号 0 到 N-1,不存在三点共线的情况。每两点之间有一条直线相连。游戏没有规定起点和终点,但限定了每次转角的方向。首先,小王需要先选择两个点分别作为起点和终点,然后从起点开始访问剩余 N-2 个点恰好一次并回到终点。访问的顺序需要满足一串给定的长度为 N-2 由 L 和 R 组成的字符串 direction,表示从起点出发之后在每个顶点上转角的方向。根据这个提示,小王希望你能够帮她找到一个可行的遍历顺序,输出顺序下标(若有多个方案,输出任意一种)。可以证明这样的遍历顺序一定是存在的。

(上图:A->B->C 右转; 下图:D->E->F 左转)

Screenshot 2020-03-20 at 17.04.58.png

示例 1:

输入:points = [[1,1],[1,4],[3,2],[2,1]], direction = "LL"

输入:[0,2,1,3]

解释:[0,2,1,3] 是符合"LL"的方案之一。在 [0,2,1,3] 方案中,0->2->1 是左转方向, 2->1->3 也是左转方向 

å¾ç.gif

示例 2:

输入:points = [[1,3],[2,4],[3,3],[2,1]], direction = "LR"

输入:[0,3,1,2]

解释:[0,3,1,2] 是符合"LR"的方案之一。在 [0,3,1,2] 方案中,0->3->1 是左转方向, 3->1->2 是右转方向

限制:

3 <= points.length <= 1000 且 points[i].length == 2
1 <= points[i][0],points[i][1] <= 10000
direction.length == points.length - 2
direction 只包含 "L","R"

思路:在比赛时想到了和官方题解一样的思路:当需要左转时我们选择当前点左边的点中最右边的点,右转时同样的道理。代码写的太丑了,一直TLE,今天补了这道题,发现比赛时真的蠢,拿叉积判断就ok了。【参考:官方题解

class Solution {
    public int[] visitOrder(int[][] points, String direction) {

        int size = 0;
        int n = points.length;
        int[] ans = new int[n];
        int len = direction.length();
        boolean[] used = new boolean[n];
        List<int[]> point = new ArrayList<>();

        for (int i = 0; i < n; i++)
            point.add(new int[]{points[i][0], points[i][1]});

        int start = 0;
        for (int i = 1; i < n; i++) {
            if (point.get(i)[0] < point.get(start)[0] ||
                    point.get(i)[0] == point.get(start)[0] &&
                            point.get(i)[1] < point.get(start)[1])
                start = i;
        }

        used[start] = true;
        ans[size++] = start;

        for (int i = 0; i < len; i++) {
            int next = -1;
            if (direction.charAt(i) == 'L') {
                for (int j = 0; j < n; j++) {
                    if (!used[j]) {
                        if (next == -1 || Cross(Sub(point.get(next), point.get(start)), Sub(point.get(j), point.get(start))) < 0)
                            next = j;
                    }
                }
            } else {
                for (int j = 0; j < n; j++) {
                    if (!used[j]) {
                        if (next == -1 || Cross(Sub(point.get(next), point.get(start)), Sub(point.get(j), point.get(start))) > 0)
                            next = j;
                    }
                }
            }
            used[next] = true;
            ans[size++] = next;
            start = next;
        }

        for (int i = 0; i < n; i++) {
            if (!used[i])
                ans[size++] = i;
        }

        return ans;


    }

    private int Cross(int[] a, int[] b) {
        return a[0] * b[1] - a[1] * b[0];
    }

    private int[] Sub(int[] a, int[] b) {
        return new int[]{a[0] - b[0], a[1] - b[1]};
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值