Medium
题目描述
给你一个二维数组 points 和一个字符串 s,其中 points[i] 表示点 i 的坐标,s[i] 表示点 i 的标签。
一个有效的正方形是指以原点 (0, 0) 为中心,边与坐标轴平行,且不包含两个具有相同标签的点的正方形。
返回有效正方形中包含的最大点数。
注意:
- 如果一个点位于正方形的边界上或内部,则认为该点在正方形内。
- 正方形的边长可以为零。
示例 1:
输入:points = [[2,2],[-1,-2],[-4,4],[-3,1],[3,-3]], s = "abdca"
输出:2
解释:边长为 4 的正方形包含两个点 points[0] 和 points[1]。
示例 2:
输入:points = [[1,1],[-2,-2],[-2,2]], s = "abb"
输出:1
解释:边长为 2 的正方形包含一个点,即 points[0]。
示例 3:
输入:points = [[1,1],[-1,-1],[2,-2]], s = "ccd"
输出:0
解释:无法创建以原点为中心的有效正方形,使其仅包含 points[0] 和 points[1] 中的一个点。
约束:
1 <= s.length, points.length <= 10^5points[i].length == 2-10^9 <= points[i][0], points[i][1] <= 10^9s.length == points.lengthpoints由不同的坐标组成s只包含小写英文字母
解题思路
解题思路
这道题需要找到以原点为中心的最大有效正方形,其中有效指的是不包含相同标签的点。
核心观察:
- 对于点
(x, y),要被包含在以原点为中心的正方形内,正方形的边长至少需要2 * max(abs(x), abs(y)) - 我们可以按照每个点到原点的"切比雪夫距离"(即
max(abs(x), abs(y)))进行排序 - 然后逐步扩大正方形,检查当前大小下是否出现重复标签
算法步骤:
- 计算每个点的切比雪夫距离,并与对应标签一起存储
- 按距离排序
- 使用二分查找或直接遍历,找到最大的有效正方形边长
- 在扩大正方形的过程中,用哈希表记录已出现的标签,一旦发现重复标签就停止
优化思路:
- 可以直接遍历所有可能的边长,对于每个边长检查包含的点是否有重复标签
- 也可以用二分查找优化,但由于需要检查标签重复性,直接遍历更简单
时间复杂度主要来自排序操作,为 O(n log n)。
代码实现
class Solution {
public:
int maxPointsInsideSquare(vector<vector<int>>& points, string s) {
int n = points.size();
vector<pair<int, char>> distanceTag;
// 计算每个点的切比雪夫距离并配对标签
for (int i = 0; i < n; i++) {
int dist = max(abs(points[i][0]), abs(points[i][1]));
distanceTag.push_back({dist, s[i]});
}
// 按距离排序
sort(distanceTag.begin(), distanceTag.end());
unordered_set<char> used;
int maxPoints = 0;
for (int i = 0; i < n; i++) {
char tag = distanceTag[i].second;
// 如果当前标签已经使用过,停止
if (used.count(tag)) {
break;
}
used.insert(tag);
maxPoints++;
}
return maxPoints;
}
};
class Solution:
def maxPointsInsideSquare(self, points: List[List[int]], s: str) -> int:
n = len(points)
distance_tag = []
# 计算每个点的切比雪夫距离并配对标签
for i in range(n):
dist = max(abs(points[i][0]), abs(points[i][1]))
distance_tag.append((dist, s[i]))
# 按距离排序
distance_tag.sort()
used = set()
max_points = 0
for dist, tag in distance_tag:
# 如果当前标签已经使用过,停止
if tag in used:
break
used.add(tag)
max_points += 1
return max_points
public class Solution {
public int MaxPointsInsideSquare(int[][] points, string s) {
int n = points.Length;
var distanceTag = new List<(int dist, char tag)>();
// 计算每个点的切比雪夫距离并配对标签
for (int i = 0; i < n; i++) {
int dist = Math.Max(Math.Abs(points[i][0]), Math.Abs(points[i][1]));
distanceTag.Add((dist, s[i]));
}
// 按距离排序
distanceTag.Sort((a, b) => a.dist.CompareTo(b.dist));
var used = new HashSet<char>();
int maxPoints = 0;
foreach (var (dist, tag) in distanceTag) {
// 如果当前标签已经使用过,停止
if (used.Contains(tag)) {
break;
}
used.Add(tag);
maxPoints++;
}
return maxPoints;
}
}
var maxPointsInsideSquare = function(points, s) {
const n = points.length;
const distanceTag = [];
// 计算每个点的切比雪夫距离并配对标签
for (let i = 0; i < n; i++) {
const dist = Math.max(Math.abs(points[i][0]), Math.abs(points[i][1]));
distanceTag.push([dist, s[i]]);
}
// 按距离排序
distanceTag.sort((a, b) => a[0] - b[0]);
const used = new Set();
let maxPoints = 0;
for (const [dist, tag] of distanceTag) {
// 如果当前标签已经使用过,停止
if (used.has(tag)) {
break;
}
used.add(tag);
maxPoints++;
}
return maxPoints;
};
复杂度分析
| 复杂度类型 | 复杂度 |
|---|---|
| 时间复杂度 | O(n log n) |
| 空间复杂度 | O(n) |
- 时间复杂度:主要来自排序操作 O(n log n),遍历过程为 O(n)
- 空间复杂度:需要额外的数组存储距离和标签对,以及哈希表存储已使用的标签