【2022/04/24-第290场单周赛】复盘

总结

这次题目的知识点比较基础。主要时间花费在了第三题,还是要看清楚变量范围条件的提示。

Q1.多个数组求交集

Q1链接

  • 题意理解:
    输出在每个所给数组中都存在的数,即取交集。

  • 初始思路:
    莫名其妙搞得很复杂,用两个哈希表来记录当前数组和下一数组存在的数,然后做与运算。浪费了很多时间。

class Solution {
public:
    vector<int> intersection(vector<vector<int>>& nums) {
        vector<int> h1(1010, 0), h2(1010, 0);
        for(int i = 0; i < nums[0].size(); ++i){
            h1[nums[0][i]] = 1;
        }
        for(int i = 1; i < nums.size(); ++i){
            for(int j = 0; j < nums[i].size(); ++j){
                h2[nums[i][j]] = h1[nums[i][j]];
            }
            for(int j = 0; j < 1010; ++j){
                h1[j] = h2[j];
                h2[j] = 0;
            }
        }
        vector<int> ret;
        for(int i = 0; i < 1010; ++i){
            if(h1[i])
                ret.push_back(i);
        }
        return ret;
    }
};
  • 改进解法:
    用哈希表记录每个数出现次数,出现次数等于数组数量的值就是结果。
class Solution {
public:
    vector<int> intersection(vector<vector<int>>& nums) {
        vector<int> h(1010,0), ret;
        for(auto i : nums) for(auto j : i) ++h[j];
        for(int i = 0; i < 1010; ++i) if(h[i] == nums.size()) ret.emplace_back(i);
        return ret;
    }
};

Q2.统计圆内格点数目

Q2链接

复盘:

  • 题意理解:
    直角坐标上给出很多圆,返回在圆内的坐标值为整数的点。

  • 初始思路:
    用一个哈希表记录点,把每个圆内的点加入到哈希表中

class Solution {
public:
    
    double dis(int x1, int y1, int x2, int y2){
        return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    }
    
    int countLatticePoints(vector<vector<int>>& circles) {
        unordered_set<int> st;
        for(auto i : circles){
            int x1 = i[0], y1 = i[1], r = i[2];
            for(int i = x1 - r; i <= x1 + r; ++i){
                for(int j = y1 - r; j <= y1 + r; ++j){
                    if(dis(x1, y1, i, j) <= r) st.insert(i * 1000 + j);
                }
            }
        }
        return st.size();
    }
};
  • 改进解法:
    根据数据范围,初始思路枚举每个圆内点重复较多,性能较差。
    若是对每个点枚举圆,则有优化空间。
    先将去顶可能点坐标上下界,圆按半径从大到小排序,然后对每个可能的点,依次枚举圆。
class Solution {
public:
    
    int countLatticePoints(vector<vector<int>>& circles) {
        int ret = 0, minx = INT_MAX, maxx = INT_MIN, miny = INT_MAX, maxy = INT_MIN;
        for(auto &c : circles){
            minx = min(minx, c[0] - c[2]);
            miny = min(miny, c[1] - c[2]);
            maxx = max(maxx, c[0] + c[2]);
            maxy = max(maxy, c[1] + c[2]);
        }
        sort(circles.begin(), circles.end(),[] (const vector<int> &a, const vector<int> &b){
            return a[2] > b[2];
        });
        for(int i = minx; i <= maxx; ++i){
            for(int j = miny; j <= maxy; ++j){
                for(auto &c : circles){
                    if((i - c[0]) * (i - c[0]) + (j - c[1]) * (j - c[1]) <= c[2] * c[2]){
                        ++ret;
                        break;
                    }
                }
            }
        }
        return ret;
    }
};

Q3.统计包含每个点的矩形数目

Q3链接

  • 题意理解:
    对于每个点(x,y),确定有多少个给出的原始数对(xi,yi)满足xi>=x && yi>=y

  • 初始思路:
    一开始没注意y的取值范围很小,直接暴力超时了。后面根据y轴分组还是做出来了,最后一分钟的提交!

class Solution {
public:
    vector<int> countRectangles(vector<vector<int>>& r, vector<vector<int>>& p) {
        int rn = r.size(), pn = p.size(), maxy = 0;
        vector<int> rh[110], ret(pn, 0);
        for(int i = 0; i < rn; ++i){
            rh[r[i][1]].push_back(r[i][0]);
            maxy = max(maxy, r[i][1]);
        }
        for(int i = 0; i <= maxy; ++i) sort(rh[i].begin(), rh[i].end());
        for(int i = 0; i < pn; ++i){
            int x = p[i][0], y = p[i][1];
            for(int j = y; j <= maxy; ++j){
                if(rh[j].empty()) continue;
                if(rh[j][0] >= x){
                    ret[i] += rh[j].size();
                    continue;
                }
                if(rh[j][rh[j].size() - 1] < x) continue;
                int l = 0, r = rh[j].size() - 1;
                while(l < r){
                    int mid = (l + r) / 2;
                    if(rh[j][mid] < x) l = mid + 1;
                    else r = mid;
                }
                
                ret[i] += rh[j].size() - l;
            }
        }
        
        return ret;
    }
};
  • 改进思路:
    对于分组的遍历也可以二分查找,进一步优化。略了。

Q4.花期内花的数目

Q4链接

  • 题意理解:
    给出区间(花期),对每个数字(游客到达时间)求出它落在多少个区间内。

  • 初始思路
    用两个数组记录左边界(开花时间)和右边界(凋谢时间),对这两个数组和游客到达时间排序。
    然后用两个指针指示开花时间和凋谢时间,对于每个游客到达时间,完成这一时间前的所有开花凋谢操作,记录花数量。

class Solution {
public:
    vector<int> fullBloomFlowers(vector<vector<int>>& f, vector<int>& p) {
        int fn = f.size(), pn = p.size();
        vector<int> k(fn), g(fn);
        vector<int> pp = p;
        unordered_map<int, int> mp;
        vector<int> ret(pn);
        for(int i = 0; i < fn; ++i){
            k[i] = f[i][0];
            g[i] = f[i][1];
        }
        sort(k.begin(), k.end());
        sort(g.begin(), g.end());
        sort(p.begin(), p.end());
        int ki = 0, gi = 0, now = 0;
        for(int i = 0; i < pn; ++i){
            if(mp.find(p[i]) != mp.end()) continue;
            while(ki < fn && k[ki] <= p[i]){
                ++now;
                ++ki;
            }
            while(gi < fn && g[gi] < p[i]){
                --now;
                ++gi;
            }
            mp[p[i]] = now;
        }
        for(int i = 0; i < pn; ++i) ret[i] = mp[pp[i]];
        return ret;
    }
};
  • 其他思路
    对于每个\(person_i\),用先于他的时间\(start\)数减去早于他的时间\(end\)数。
class Solution {
public:
    vector<int> fullBloomFlowers(vector<vector<int>> &flowers, vector<int> &persons) {
        int n = flowers.size();
        vector<int> starts(n), ends(n);
        for (int i = 0; i < n; ++i) {
            starts[i] = flowers[i][0];
            ends[i] = flowers[i][1];
        }
        sort(starts.begin(), starts.end());
        sort(ends.begin(), ends.end());

        n = persons.size();
        vector<int> ans(n);
        for (int i = 0; i < n; ++i)
            ans[i] = (upper_bound(starts.begin(), starts.end(), persons[i]) - starts.begin()) -
                     (lower_bound(ends.begin(), ends.end(), persons[i]) - ends.begin());
        return ans;
    }
};
posted on 2022-04-29 11:15  damnglamour  阅读(29)  评论(0)    收藏  举报