题目:
给你一个二维数组 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 的正方形包含 1 个点 points[0]
。
示例 3:
输入:points = [[1,1],[-1,-1],[2,-2]], s = “ccd”
输出:0
解释:
任何正方形都无法只包含 points[0]
和 points[1]
中的一个点,所以合法正方形中都不包含任何点。
提示:
1 <= s.length, points.length <= 105
points[i].length == 2
-109 <= points[i][0], points[i][1] <= 109
s.length == points.length
points
中的点坐标互不相同。s
只包含小写英文字母。
模拟正方形增长
思路:
我们想象一个正方形边长从 0 开始增长,然后逐步覆盖点,在正方形中的点 所代表的字母必须不一样
所以要利用哈希表去重,返回的点数 其实就是哈希表的大小
由于边长是以 1 的基准增长,那么只要下一轮出现了重复字母,就只能返回上一轮边长下的 字母数
覆盖点的这个操作 需要优化,利用 vector<pair<int, char>> lenChar 重新组织 points 和 s, 让点距离原点的距离有序排列,这样在模拟时就只需要正常增长,lenChar 的索引就是增长方向
代码:
class Solution {
public:
static bool cmp(pair<int, char>& a, pair<int, char>& b) {
return a.first < b.first;
}
int maxPointsInsideSquare(vector<vector<int>>& points, string s) {
// 点在正方形内的必要条件,横纵坐标绝对值都小于边长
// 一步步扩大正方形,用哈希表记录存在于内的字符,出现重复就停止
int len = 0, n = s.size();
unordered_set<char> uniChar;
vector<pair<int, char>> lenChar(n);
for (int i = 0; i < n; i++) {
lenChar[i] = make_pair(max(abs(points[i][0]), abs(points[i][1])), s[i]);
}
sort(lenChar.begin(), lenChar.end(), cmp);
int idx = 0, ans = 0;
while (idx < n) {
while (idx < n && lenChar[idx].first <= len) {
if (uniChar.find(lenChar[idx].second) != uniChar.end()) {
return ans;
}
uniChar.insert(lenChar[idx].second);
idx++;
}
len++;
ans = uniChar.size();
}
return ans;
}
};
维护次小半径
思路:
我们定义正方形的半径为边长的一半,每个点所在正方形,其半径为点 (x,y) 到 (0,0) 的「切比雪夫距离」,即 max(∣x∣,∣y∣)
对于每个字符,计算字符到原点的最小的半径,并维护所有字符的次小半径。根据题意,半径小于次小半径的正方形,是合法正方形。
最后遍历所有字符的最小距离,返回在合法正方形内的个数。
代码:
class Solution {
public:
int maxPointsInsideSquare(vector<vector<int>>& points, string s) {
vector<int> min1(26, 1000000001);
int min2 = 1000000001;
int n = s.length();
for (int i = 0; i < n; ++i) {
int x = points[i][0], y = points[i][1], j = s[i] - 'a';
int d = max(abs(x), abs(y));
if (d < min1[j]) {
min2 = min(min2, min1[j]);
min1[j] = d;
} else if (d < min2) {
min2 = d;
}
}
int res = 0;
for (int d : min1) {
if (d < min2) {
++res;
}
}
return res;
}
};