Facebook Pixel

3143. Maximum Points Inside the Square


Problem Description

You are given a 2D array points and a string s where points[i] represents the coordinates of point i, and s[i] represents the tag of point i.

A valid square is a square centered at the origin (0, 0), has edges parallel to the axes, and does not contain two points with the same tag.

Return the maximum number of points contained in a valid square.

Note:

  • A point is considered to be inside the square if it lies on or within the square's boundaries.
  • The side length of the square can be zero.

Intuition

To solve this problem, consider the properties of the squares centered at the origin with edges parallel to the axes. For any point (x, y), determine the edge length of the square such that the point lies on the boundary of or within the square. This can be calculated as max(abs(x), abs(y)), giving the distance to the furthest axis-aligned component from the origin.

The core idea is to group points based on this distance and consider consecutive increasing distances, starting from zero, adding layers of points into the square as long as a valid square configuration is maintained. A valid configuration requires that no two points within the current square share the same tag.

By storing these distances and corresponding points in a hash table and keeping track of the tags using a set while iterating through sorted distances, we can count the maximum number of valid points. If any duplicate tags are encountered while processing a group of points, the traversal stops for that square size, and the current count is returned as the solution.

Learn more about Binary Search and Sorting patterns.

Solution Approach

The solution uses a combination of a hash table and sorting to efficiently determine the maximum number of points that can fit inside a valid square while adhering to the tag constraint. Here’s the detailed breakdown:

  1. Hash Table Construction:

    • Iterate over each point (x, y) in the points array.
    • Calculate the distance d from the origin to the boundary of the prospective square. This distance is max(abs(x), abs(y)).
    • Use this distance d as a key in a hash table g, where each key stores a list of indices of points that have the same distance d from the origin. This grouping helps in processing points layer by layer starting from the smallest squares.
  2. Distance Sorting:

    • Sort the distances stored in the hash table. This ensures that we process the points starting from the smallest possible square (which is crucial for maximizing the number of points).
  3. Maintaining Validity with Tags:

    • Initialize a set vis to keep track of the tags of the points included in the current valid square.
    • Initialize a counter ans to store the maximum number of valid points inside a square.
    • Iterate over each distance d in the sorted order:
      • Retrieve all point indices corresponding to this distance.
      • For each point index:
        • Check the tag s[i] of the point. If this tag is already in vis, it implies adding this point would violate the unique tag constraint, so break the loop and return ans.
        • Otherwise, add the tag to vis.
      • Add the number of points processed at this distance to ans.
  4. Result:

    • After processing all possible layers without violating the constraints, ans contains the maximum number of points that can fit in a valid square.

The use of a hash table helps in efficiently grouping points, while sorting ensures the correctness of layering points into the square.

Ready to land your dream job?

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

Start Evaluator

Example Walkthrough

Let's illustrate the solution approach with a small example.

Suppose you have the following points represented by a 2D array points and their corresponding tags in a string s:

points = [[1, 2], [-1, -2], [3, 1], [-3, 1]]
s = "abcd"

Step-by-Step Breakdown:

  1. Hash Table Construction:

    • Calculate the distance d from the origin for each point, using the formula max(abs(x), abs(y)).
      • For point (1, 2), d = max(abs(1), abs(2)) = 2.
      • For point (-1, -2), d = max(abs(-1), abs(-2)) = 2.
      • For point (3, 1), d = max(abs(3), abs(1)) = 3.
      • For point (-3, 1), d = max(abs(-3), abs(1)) = 3.
    • Build a hash table g:
      • g = {2: [0, 1], 3: [2, 3]}.
  2. Distance Sorting:

    • Sort the keys (distances) in g to get [2, 3].
  3. Maintaining Validity with Tags:

    • Initialize vis = set() to track unique tags.

    • Initialize ans = 0 to store the maximum valid points.

    • Iterate over sorted distances:

      For distance 2:

      • Points with indices [0, 1] correspond to tags 'a' and 'b'.
      • Neither 'a' nor 'b' are in vis.
      • Add 'a' and 'b' to vis.
      • Increment ans by 2 (ans = 2).

      For distance 3:

      • Points with indices [2, 3] correspond to tags 'c' and 'd'.
      • Neither 'c' nor 'd' are in vis.
      • Add 'c' and 'd' to vis.
      • Increment ans by 2 (ans = 4).
  4. Result:

    • After processing, ans is 4. This is the maximum number of points that can fit in a valid square at the origin with no duplicate tags.

This approach ensures we count the maximum number of points following the rules of tags and distance from the origin. The key lies in grouping points by their distance from the origin and maintaining a unique set of tags.

Solution Implementation

1from collections import defaultdict
2from typing import List
3
4class Solution:
5    def maxPointsInsideSquare(self, points: List[List[int]], s: str) -> int:
6        point_groups = defaultdict(list)  # Dictionary to group points by their distance from the origin
7        # Iterate over the list of points with their indices
8        for index, (x, y) in enumerate(points):
9            # Group points by the maximum of the absolute x and y coordinates
10            point_groups[max(abs(x), abs(y))].append(index)
11      
12        visited_chars = set()  # Set to keep track of visited characters in 's'
13        max_points = 0  # Counter to track the number of points inside the square
14      
15        # Iterate over the sorted distances (keys) in the dictionary
16        for distance in sorted(point_groups):
17            indices = point_groups[distance]
18          
19            for i in indices:
20                # Check if the character at this index in 's' is already visited
21                if s[i] in visited_chars:
22                    return max_points  # Return the count if the character is already visited
23              
24                visited_chars.add(s[i])  # Mark the character as visited
25          
26            max_points += len(indices)  # Increment the count by the number of points in this distance group
27      
28        return max_points  # Return the total number of points counted inside the square
29
1import java.util.*;
2
3class Solution {
4    public int maxPointsInsideSquare(int[][] points, String s) {
5        // TreeMap to store lists of indices by their maximum absolute coordinate
6        TreeMap<Integer, List<Integer>> coordinateMap = new TreeMap<>();
7
8        // Populate the TreeMap with point indices grouped by the maximum absolute value of their coordinates
9        for (int i = 0; i < points.length; ++i) {
10            int x = points[i][0], y = points[i][1];
11            // Determine the maximum absolute value between the x and y coordinates
12            int maxCoordinate = Math.max(Math.abs(x), Math.abs(y));
13            // Add the index to the corresponding list in the TreeMap
14            coordinateMap.computeIfAbsent(maxCoordinate, k -> new ArrayList<>()).add(i);
15        }
16
17        // Boolean array to track the alphabetic characters that have been seen (0 for 'a', 1 for 'b', ..., 25 for 'z')
18        boolean[] visited = new boolean[26];
19        int maxPoints = 0;
20
21        // Iterate over the values (lists of indices) in order of their keys (maximum absolute coordinates)
22        for (List<Integer> indices : coordinateMap.values()) {
23            for (int index : indices) {
24                // Get the current character from the string s and calculate its position in the alphabet
25                int charIndex = s.charAt(index) - 'a';
26
27                // If the character has been seen before, return the current maxPoints as no new characters can be added
28                if (visited[charIndex]) {
29                    return maxPoints;
30                }
31                // Mark the character as seen
32                visited[charIndex] = true;
33            }
34            // Increment the count of maxPoints by the size of the list of indices
35            maxPoints += indices.size();
36        }
37
38        // Return the total number of points that can fit inside the square
39        return maxPoints;
40    }
41}
42
1#include <vector>
2#include <string>
3#include <map>
4
5class Solution {
6public:
7    // Function to determine the maximum number of points that can be inside a square.
8    int maxPointsInsideSquare(std::vector<std::vector<int>>& points, std::string s) {
9        std::map<int, std::vector<int>> groupedPoints; // Map to hold points based on maximum of their absolute coordinates.
10
11        // Group points by the maximum of absolute x or y values as keys.
12        for (int i = 0; i < points.size(); ++i) {
13            auto& point = points[i];
14            int key = std::max(abs(point[0]), abs(point[1]));
15            groupedPoints[key].push_back(i);
16        }
17
18        bool visited[26] = {}; // Array to track visited characters (a-z).
19        int result = 0; // Initialize the result.
20
21        // Iterate through each group of points.
22        for (auto& [key, indices] : groupedPoints) {
23            for (int i : indices) {
24                int charIndex = s[i] - 'a'; // Determine the character index corresponding to point.
25                if (visited[charIndex]) { // If character has been seen already, return answer.
26                    return result;
27                }
28                visited[charIndex] = true; // Mark this character as visited.
29            }
30            result += indices.size(); // Add number of points to the result for this key.
31        }
32        return result; // Return the final computed result.
33    }
34};
35
1function maxPointsInsideSquare(points: number[][], s: string): number {
2    const n = points.length;
3
4    // Map to group indices of points by the maximum absolute coordinate value
5    const indexMap: Map<number, number[]> = new Map();
6
7    // Populate the map with indices of points
8    for (let i = 0; i < n; ++i) {
9        const [x, y] = points[i];
10        // Calculate the key as the maximum of the absolute x or y
11        const key = Math.max(Math.abs(x), Math.abs(y));
12      
13        // Initialize array in the map at this key if it doesn't exist
14        if (!indexMap.has(key)) {
15            indexMap.set(key, []);
16        }
17      
18        // Append the index to the relevant key's array
19        indexMap.get(key)!.push(i);
20    }
21
22    // Get sorted keys of the map
23    const keys = Array.from(indexMap.keys()).sort((a, b) => a - b);
24
25    // Array to check if a character in the input string s has been visited/used
26    const visited: boolean[] = Array(26).fill(false);
27  
28    let maxPoints = 0;
29
30    // Iterate over each key
31    for (const key of keys) {
32        const indices = indexMap.get(key)!; // Retrieve indices for the current key
33      
34        // Check each index to see if we've seen the corresponding character before
35        for (const i of indices) {
36            const charIndex = s.charCodeAt(i) - 'a'.charCodeAt(0);
37
38            // If character already visited, return the count so far
39            if (visited[charIndex]) {
40                return maxPoints;
41            }
42
43            // Mark the character as visited
44            visited[charIndex] = true;
45        }
46
47        // Increment maxPoints count by the number of points at this key
48        maxPoints += indices.length;
49    }
50
51    // Return the total number of points
52    return maxPoints;
53}
54

Time and Space Complexity

The time complexity of the code is O(n × log n). This is because the code sorts a list containing the keys of the defaultdict g, which has at most n elements, where each element corresponds to a unique maximum distance from the origin for a point. Sorting this list requires O(n × log n) operations. Then, iterating through each list in g and checking membership in a set vis contributes O(n) operations.

The space complexity of the code is O(n). This is due to the storage of the indices of points in the defaultdict g, which holds indices for each potential value of maximum distance, and also due to the storage of characters in the set vis, both of which are proportional to n.

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


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:
Question 1 out of 10

Which of the following uses divide and conquer strategy?


Recommended Readings

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


Load More