1266. Minimum Time Visiting All Points*
https://leetcode.com/problems/minimum-time-visiting-all-points/
题目描述
On a plane there are n points with integer coordinates points[i] = [xi, yi]
. Your task is to find the minimum time in seconds to visit all points.
You can move according to the next rules:
In one second always you can either move vertically, horizontally by one unit or diagonally (it means to move one unit vertically and one unit horizontally in one second).
You have to visit the points in the same order as they appear in the array.
![](https://i-blog.csdnimg.cn/blog_migrate/b5f66fc25a13a20d290668351d88d95b.png)
Input: points = [[1,1],[3,4],[-1,0]]
Output: 7
Explanation: One optimal path is [1,1] -> [2,2] -> [3,3] -> [3,4] -> [2,3] -> [1,2] -> [0,1] -> [-1,0]
Time from [1,1] to [3,4] = 3 seconds
Time from [3,4] to [-1,0] = 4 seconds
Total time = 7 seconds
Example 2:
Input: points = [[3,2],[-2,2]]
Output: 5
Constraints:
points.length == n
1 <= n <= 100
points[i].length == 2
-1000 <= points[i][0], points[i][1] <= 1000
解题思路
这道题标注为 Easy, 但是要愉快的求解, 还是需要细细观察, 发现规律. 首先注意题目的要求:
- 移动时能左右, 上下以及对角移动
- 移动的顺序和点在数组中出现的顺序相同.
基于以上的要求, 可以将问题简化成 “如何用最少的步数从 A 点达到 B 点(或者 D 点)”, 如下图:
![](https://i-blog.csdnimg.cn/blog_migrate/bb0f23ede121fbf704561171dce4c61a.png)
如上图, 先看 A 如何以最小步数移动到 B. 首先可以分别通过 A 和 B 画两条斜线, 用来显示按斜线方向移动的轨迹. 可以发现, 按照路线 A -> a1 -> B
移动, 步数是最少的, 另外还可以观察到的一点是, 按这个路线移动使用的步数刚好等于 BC
的长度, 这是因为 A -> a1
的步数与 C -> a1
的步数是相同的. 从这里我们可以得到一个结论:
- 在
BF
上的任意一点, 假设为 K, 坐标设置为 ( x K , y K ) (x_K, y_K) (xK,yK), 从 A (假设坐标设置为 ( x A , y A ) (x_A, y_A) (xA,yA)) 移动到 K 的最小步数刚好等于 abs ( y K − y A ) \text{abs}(y_K - y_A) abs(yK−yA);
下面再来看 A 是如何以最小的步数移动到 D 的. 首先仍然是通过 A 和 D 画两条斜线, 可以发现, 按照路线 A -> c1 -> D
移动, 所用的步数最少. 另外还可以观察到的一点是, 按照这个路线移动的步数刚好等于 AE
的长度, 这是因为 c1 -> D
的步数和 c1 -> E
的步数是相同的. 从这里我们可以得到第二个结论:
- 在
DF
上移动的任意一点, 假设为 K, 坐标设置为 ( x K , y K ) (x_K, y_K) (xK,yK), 从 A (假设坐标设置为 ( x A , y A ) (x_A, y_A) (xA,yA)) 移动到 K 的最小步数刚好等于 abs ( x K − x A ) \text{abs}(x_K - x_A) abs(xK−xA).
于是剩下的问题是, 如何判断第二个点的位置是在 B 处还是在 D 处. 方法很简单, 如果在 B 处, 那么总会满足条件 BC > AC
; 而如果在 D 处, 那么总会有 AE > DE
. 而 BC
刚好是 A -> B
的最小步数, AE
刚好是 A -> D
的最小步数.
翻译过来就是我们只需要比较两个点的横坐标之差与纵坐标之差哪个更大即可求出最小步数:
min_step = std::max(std::abs(A[0] - B[0]), std::abs(A[1] - B[1]));
完整实现代码如下.
C++ 实现 1
了解上一节的原理之后, 代码就很好写了. 引入一个辅助函数 time
来记录两点之间移动所需要的最小步数, 之后统计访问数组中所有点所需要的最小时间.
class Solution {
private:
int time(const vector<int> &p1, const vector<int> &p2) {
if (p1.empty() || p2.empty()) return 0;
return std::max(std::abs(p2[0] - p1[0]), std::abs(p2[1] - p1[1]));
}
public:
int minTimeToVisitAllPoints(vector<vector<int>>& points) {
if (points.size() < 2) return 0;
int min_time = 0;
for (int i = 1; i < points.size(); ++ i)
min_time += time(points[i - 1], points[i]);
return min_time;
}
};