小王来到了游乐园,她玩的第一个项目是模拟推销员。有一个二维平面地图,其中散布着 N
个推销点,编号 0
到N-1
,不存在三点共线的情况。每两点之间有一条直线相连。游戏没有规定起点和终点,但限定了每次转角的方向。首先,小王需要先选择两个点分别作为起点和终点,然后从起点开始访问剩余N-2
个点恰好一次并回到终点。访问的顺序需要满足一串给定的长度为 N-2
由 L
和 R
组成的字符串direction
,表示从起点出发之后在每个顶点上转角的方向。根据这个提示,小王希望你能够帮她找到一个可行的遍历顺序,输出顺序下标(若有多个方案,输出任意一种)。可以证明这样的遍历顺序一定是存在的。
![Screenshot 2020-03-20 at 17.04.58.png](https://pic.leetcode- cn.com/595b60797d4a461287864a8cd05bba1d3b8760104ff83f43b902fd68477be9c3-Screenshot%202020-03-20%20at%2017.04.58.png)
(上图:A->B->C 右转; 下图:D->E->F 左转)
示例 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](https://pic.leetcode- cn.com/c01c1efc423b916267c2a3a170266c925c368d62afa047c267cc1020970e55d9-%E5%9B%BE%E7%89%87.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"
题意概述 平面上有 N 个点,找到一条访问 N 个点的路径,使得路径的转角满足给定的转角序列。
题解 我们保持一个理想的状态:转向时,剩余的点都位于要求方向的一侧(即剩余点都符合当前这次的转向要求)。那么当前这次转向选择什么点,可以使下一次转向依旧满足这个理想的状态,从而可以不断的递归找下去。
若下一次转向的要求方向是 L
(R
),则这次转向的点中选择相对方向最右(最左)的点即可。
如图所示,当前位于 B
点且转向方向为 R
,其余点都位于 \overrightarrow{AB 的右侧,其中点 C
、D
分别是相对方向最左和最右的点。若下一次转向方向为 L
,则这次选择 D
点,可使剩余点都位于 \overrightarrow{BD 的左侧;若下一次转向方向为 R
,则这次选择 C
点,可使剩余点都位于 \overrightarrow{BC 的右侧。
这里的最左或最右的选择,可利用利用叉积的性质:若向量 \overrightarrow{BC 和向量 \overrightarrow{BD 的叉积结果为正,则从向量 \overrightarrow{BC 到向量 \overrightarrow{BD 为逆时针旋转( \overrightarrow{BD 在 \overrightarrow{BC 的左侧);反之若结果为负,则从向量 \overrightarrow{BC 到向量 \overrightarrow{BD 为顺时针旋转( \overrightarrow{BD 在 \overrightarrow{BC 的右侧)。
[] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 class Solution {private : pair<int , int > Sub (pair<int , int > a, pair<int , int > b) { return make_pair (a.first - b.first, a.second - b.second); } int Cross (pair<int , int > a, pair<int , int > b) { return a.first * b.second - a.second * b.first; } public : vector<int > visitOrder (vector< vector<int > >& points, string dir) { int n = points.size (); vector<bool > used (n, false ) ; vector< pair<int , int > > point; vector<int > order; for (int i=0 ; i<n; ++i) { point.push_back ( make_pair (points[i][0 ], points[i][1 ]) ); } int start = 0 ; for (int i=1 ; i<n; ++i) { if (point[i] < point[start]) { start = i; } } used[start] = true ; order.push_back (start); for (int i=0 ; i<dir.size (); ++i) { int next = -1 ; if (dir[i] == 'L' ) { for (int j=0 ; j<n; ++j) { if (!used[j]) { if (next == -1 || Cross (Sub (point[next], point[start]), Sub (point[j], point[start])) < 0 ) { next = j; } } } } else if (dir[i] == 'R' ) { for (int j=0 ; j<n; ++j) { if (!used[j]) { if (next == -1 || Cross (Sub (point[next], point[start]), Sub (point[j], point[start])) > 0 ) { next = j; } } } } used[next] = true ; order.push_back (next); start = next; } for (int i=0 ; i<n; ++i) { if (used[i] == false ) { order.push_back (i); } } return order; } };
[] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Solution : def sub (self, a, b ): return [a[0 ]-b[0 ], a[1 ]-b[1 ]] def cross (self, a, b ): return a[0 ] * b[1 ] - a[1 ] * b[0 ] def visitOrder (self, points: List [List [int ]], direction: str ) -> List [int ]: n = len (points) used = [False ] * n order = [] start = 0 for i in range (0 ,n): if points[i][0 ] < points[start][0 ]: start = i used[start] =True order.append(start) for i in direction: nxt = -1 if i=='L' : for j in range (0 ,n): if not used[j]: if nxt==-1 or self.cross(self.sub(points[nxt],points[start]), self.sub(points[j],points[start])) <0 : nxt = j else : for j in range (0 ,n): if not used[j]: if nxt==-1 or self.cross(self.sub(points[nxt],points[start]), self.sub(points[j],points[start])) >0 : nxt = j used[nxt] = True order.append(nxt) start = nxt for i in range (0 ,n): if not used[i]: order.append(i) return order
复杂度分析