Facebook Pixel

1266. Minimum Time Visiting All Points

Problem Description

You are given n points on a 2D plane, where each point is represented as points[i] = [xi, yi] with integer coordinates. Your task is to find the minimum time in seconds needed to visit all points in the exact order they appear in the array.

The movement rules are:

  • In 1 second, you can make one of three moves:
    • Move vertically by 1 unit (up or down)
    • Move horizontally by 1 unit (left or right)
    • Move diagonally by sqrt(2) units (which means moving 1 unit vertically and 1 unit horizontally simultaneously)

Key constraints:

  • You must visit the points in the given order
  • You can pass through points that appear later in the array, but they don't count as visited until you reach them in sequence

The solution leverages the fact that for any two points p1 = (x1, y1) and p2 = (x2, y2), the minimum time to travel between them is max(|x1 - x2|, |y1 - y2|). This is because:

  • If the horizontal distance dx = |x1 - x2| and vertical distance dy = |y1 - y2| are different, you can move diagonally for min(dx, dy) seconds (covering both x and y distance simultaneously), then move in the remaining direction for |dx - dy| seconds
  • The total time is min(dx, dy) + |dx - dy| = max(dx, dy)

The solution calculates this maximum distance for each consecutive pair of points and sums them up to get the total minimum time.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight comes from understanding how diagonal movement works. Since we can move diagonally (covering both x and y distance in a single second), we should use diagonal moves as much as possible to minimize time.

Let's think about moving from point A to point B. We need to cover some horizontal distance dx and some vertical distance dy. Since diagonal movement allows us to cover 1 unit in both x and y directions simultaneously, we can move diagonally for min(dx, dy) seconds. After these diagonal moves, we've covered equal distances in both directions, but we still have remaining distance in one direction: max(dx, dy) - min(dx, dy).

For example, if we need to move 5 units horizontally and 3 units vertically:

  • Move diagonally for 3 seconds (covers 3 units in both x and y)
  • Move horizontally for 2 more seconds (covers the remaining 2 units in x)
  • Total time: 3 + 2 = 5 seconds, which equals max(5, 3)

This pattern holds for any two points: the minimum time is always max(dx, dy) because:

  • We use diagonal moves for min(dx, dy) seconds
  • We use straight moves (either horizontal or vertical) for max(dx, dy) - min(dx, dy) seconds
  • Total: min(dx, dy) + (max(dx, dy) - min(dx, dy)) = max(dx, dy)

Since we must visit points in order, the total minimum time is simply the sum of minimum times between each consecutive pair of points. This gives us the elegant solution: sum up max(|x1 - x2|, |y1 - y2|) for all consecutive point pairs.

Learn more about Math patterns.

Solution Approach

The implementation follows a straightforward simulation approach based on our understanding that the minimum distance between any two points is max(dx, dy).

Algorithm Steps:

  1. Iterate through consecutive point pairs: We need to calculate the distance between each consecutive pair of points in the given order. Python's pairwise() function makes this elegant by automatically creating pairs (points[0], points[1]), (points[1], points[2]), and so on.

  2. Calculate distance for each pair: For each pair of points p1 = (x1, y1) and p2 = (x2, y2):

    • Calculate the horizontal distance: dx = |p1[0] - p2[0]|
    • Calculate the vertical distance: dy = |p1[1] - p2[1]|
    • The minimum time between these points is max(dx, dy)
  3. Sum all distances: Since we must visit points in order, the total minimum time is the sum of all individual minimum times between consecutive points.

Implementation Details:

def minTimeToVisitAllPoints(self, points: List[List[int]]) -> int:
    return sum(
        max(abs(p1[0] - p2[0]), abs(p1[1] - p2[1])) 
        for p1, p2 in pairwise(points)
    )

The solution uses:

  • pairwise(points): Creates an iterator of consecutive pairs from the points list
  • abs(): Computes absolute difference to get distance regardless of direction
  • max(): Selects the larger of the two distances (horizontal vs vertical)
  • sum(): Aggregates all the minimum distances between consecutive points

Time Complexity: O(n) where n is the number of points, as we visit each point once.

Space Complexity: O(1) as we only use constant extra space for calculations.

This approach efficiently solves the problem by recognizing that diagonal movement optimization naturally leads to the max(dx, dy) formula for any two points.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a concrete example with points = [[1,1], [3,4], [-1,0]].

We need to visit these points in order: (1,1) → (3,4) → (-1,0).

Step 1: Calculate distance from point (1,1) to point (3,4)

  • Horizontal distance: dx = |1 - 3| = 2
  • Vertical distance: dy = |1 - 4| = 3
  • Minimum time: max(2, 3) = 3 seconds

To understand why this is 3 seconds:

  • We can move diagonally for 2 seconds (covering 2 units in both x and y directions)
    • After 2 diagonal moves: we're at (3,3)
  • Then move vertically for 1 more second to reach (3,4)
  • Total: 2 + 1 = 3 seconds

Step 2: Calculate distance from point (3,4) to point (-1,0)

  • Horizontal distance: dx = |3 - (-1)| = 4
  • Vertical distance: dy = |4 - 0| = 4
  • Minimum time: max(4, 4) = 4 seconds

Since both distances are equal, we can move diagonally for all 4 seconds:

  • 4 diagonal moves take us from (3,4) to (-1,0)

Step 3: Sum all minimum times

  • Total time = 3 + 4 = 7 seconds

Using our solution code:

def minTimeToVisitAllPoints(points):
    return sum(
        max(abs(p1[0] - p2[0]), abs(p1[1] - p2[1])) 
        for p1, p2 in pairwise(points)
    )

# With points = [[1,1], [3,4], [-1,0]]
# pairwise creates: ((1,1), (3,4)) and ((3,4), (-1,0))
# First pair: max(|1-3|, |1-4|) = max(2, 3) = 3
# Second pair: max(|3-(-1)|, |4-0|) = max(4, 4) = 4
# Sum: 3 + 4 = 7

The answer is 7 seconds.

Solution Implementation

1class Solution:
2    def minTimeToVisitAllPoints(self, points: List[List[int]]) -> int:
3        """
4        Calculate minimum time to visit all points in order.
5      
6        Time is calculated using Chebyshev distance (diagonal moves allowed).
7        The minimum time between two points is the maximum of absolute differences
8        in x and y coordinates.
9      
10        Args:
11            points: List of [x, y] coordinates to visit in order
12          
13        Returns:
14            Minimum time (seconds) to visit all points
15        """
16        total_time = 0
17      
18        # Iterate through consecutive pairs of points
19        for i in range(len(points) - 1):
20            current_point = points[i]
21            next_point = points[i + 1]
22          
23            # Calculate absolute differences in x and y coordinates
24            x_distance = abs(current_point[0] - next_point[0])
25            y_distance = abs(current_point[1] - next_point[1])
26          
27            # Time needed is the maximum of x and y distances (Chebyshev distance)
28            # This accounts for diagonal movement being allowed
29            time_between_points = max(x_distance, y_distance)
30          
31            total_time += time_between_points
32      
33        return total_time
34
1class Solution {
2    /**
3     * Calculates the minimum time required to visit all points in order.
4     * Movement is allowed in 8 directions: horizontally, vertically, and diagonally.
5     * Each move takes 1 second.
6     * 
7     * @param points 2D array where each element represents a point [x, y]
8     * @return minimum time in seconds to visit all points in order
9     */
10    public int minTimeToVisitAllPoints(int[][] points) {
11        int totalTime = 0;
12      
13        // Iterate through consecutive pairs of points
14        for (int i = 1; i < points.length; i++) {
15            // Calculate horizontal distance between current and previous point
16            int horizontalDistance = Math.abs(points[i][0] - points[i - 1][0]);
17          
18            // Calculate vertical distance between current and previous point
19            int verticalDistance = Math.abs(points[i][1] - points[i - 1][1]);
20          
21            // Minimum time is the maximum of horizontal and vertical distances
22            // This works because we can move diagonally to cover both distances simultaneously
23            // until one is exhausted, then move straight for the remaining distance
24            totalTime += Math.max(horizontalDistance, verticalDistance);
25        }
26      
27        return totalTime;
28    }
29}
30
1class Solution {
2public:
3    int minTimeToVisitAllPoints(vector<vector<int>>& points) {
4        int totalTime = 0;
5      
6        // Iterate through consecutive pairs of points
7        for (int i = 1; i < points.size(); ++i) {
8            // Calculate the horizontal distance between current and previous point
9            int horizontalDistance = abs(points[i][0] - points[i - 1][0]);
10          
11            // Calculate the vertical distance between current and previous point
12            int verticalDistance = abs(points[i][1] - points[i - 1][1]);
13          
14            // The minimum time to travel between two points is the maximum of 
15            // horizontal and vertical distances (due to diagonal movement capability)
16            // We can move diagonally (1 unit in both x and y) or straight (1 unit in x or y)
17            // So the time required is determined by the larger dimension
18            totalTime += max(horizontalDistance, verticalDistance);
19        }
20      
21        return totalTime;
22    }
23};
24
1/**
2 * Calculates the minimum time needed to visit all points in order.
3 * Movement is allowed in 8 directions (horizontal, vertical, and diagonal).
4 * Each move takes 1 second.
5 * 
6 * @param points - Array of 2D coordinates [x, y] to visit in order
7 * @returns The minimum time in seconds to visit all points
8 */
9function minTimeToVisitAllPoints(points: number[][]): number {
10    // Initialize total time counter
11    let totalTime: number = 0;
12  
13    // Iterate through consecutive point pairs
14    for (let i: number = 1; i < points.length; i++) {
15        // Calculate absolute difference in x-coordinates
16        const deltaX: number = Math.abs(points[i][0] - points[i - 1][0]);
17      
18        // Calculate absolute difference in y-coordinates  
19        const deltaY: number = Math.abs(points[i][1] - points[i - 1][1]);
20      
21        // The minimum time is the maximum of the two distances
22        // (diagonal moves cover both x and y simultaneously)
23        totalTime += Math.max(deltaX, deltaY);
24    }
25  
26    return totalTime;
27}
28

Time and Space Complexity

The time complexity is O(n), where n is the number of points. The algorithm iterates through consecutive pairs of points using pairwise(points), which generates n-1 pairs from n points. For each pair, it calculates the maximum of the absolute differences in x and y coordinates, which is a constant time operation O(1). Therefore, the overall time complexity is O(n-1) * O(1) = O(n).

The space complexity is O(1). The pairwise function is a generator that yields pairs lazily without creating a new list to store all pairs at once. The sum function accumulates the result using a single variable. The only additional space used is for temporary variables p1 and p2 to hold the current pair of points, which requires constant space regardless of the input size.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Misunderstanding the Distance Formula

A common mistake is trying to use Euclidean distance or Manhattan distance instead of Chebyshev distance. Developers might incorrectly attempt:

  • Euclidean distance: sqrt((x2-x1)^2 + (y2-y1)^2) - This doesn't account for the fact that diagonal moves take only 1 second
  • Manhattan distance: |x2-x1| + |y2-y1| - This assumes no diagonal movement is possible

Solution: Remember that diagonal movement allows covering both x and y distance simultaneously in 1 second, leading to max(|x2-x1|, |y2-y1|).

2. Attempting to Find Optimal Path Across All Points

Some developers mistakenly try to find the globally optimal path visiting all points, treating this as a Traveling Salesman Problem variant. They might attempt dynamic programming or graph algorithms.

Solution: The problem explicitly states points must be visited in the given order. Simply calculate distances between consecutive points.

3. Off-by-One Errors in Loop Iteration

When iterating through point pairs, it's easy to make indexing errors:

# Wrong: Goes out of bounds
for i in range(len(points)):
    time += max(abs(points[i][0] - points[i+1][0]), ...)  # IndexError when i = len(points)-1

# Wrong: Misses the last pair
for i in range(len(points) - 2):  # Should be len(points) - 1
    time += max(...)

Solution: Use range(len(points) - 1) or utilize Python's pairwise() function for cleaner code.

4. Integer Division or Type Confusion

Some might mistakenly think diagonal distance needs special handling:

# Wrong: Trying to calculate diagonal steps separately
diagonal_steps = min(x_distance, y_distance)
remaining_steps = abs(x_distance - y_distance)
time = diagonal_steps * sqrt(2) + remaining_steps  # Incorrect!

Solution: The problem states diagonal movement takes 1 second (not sqrt(2) seconds), even though it covers sqrt(2) distance. The time calculation remains max(dx, dy).

5. Forgetting to Handle Edge Cases

Not considering arrays with only one point or empty arrays:

# This would fail for single-point arrays
for i in range(len(points) - 1):  # Loop doesn't execute if len(points) = 1
    # ...

Solution: Single point arrays should return 0 (no movement needed). The standard implementation handles this correctly as the loop simply doesn't execute.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Is the following code DFS or BFS?

void search(Node root) {
  if (!root) return;
  visit(root);
  root.visited = true;
  for (Node node in root.adjacent) {
    if (!node.visited) {
      search(node);
    }
  }
}

Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More