正方形中的最多点数

2024-08-03

题目:

给你一个二维数组 points 和一个字符串 s ,其中 points[i] 表示第 i 个点的坐标,s[i] 表示第 i 个点的 标签

如果一个正方形的中心在 (0, 0) ,所有边都平行于坐标轴,且正方形内 存在标签相同的两个点,那么我们称这个正方形是 合法 的。

请你返回 合法 正方形中可以包含的 最多 点数。

注意:

  • 如果一个点位于正方形的边上或者在边以内,则认为该点位于正方形内。
  • 正方形的边长可以为零。

示例 1:

img

输入:points = [[2,2],[-1,-2],[-4,4],[-3,1],[3,-3]], s = “abdca”

输出:2

解释:

边长为 4 的正方形包含两个点 points[0]points[1]

示例 2:

img

输入: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;
    }
};