leetcode 第 387 场周赛 题解

leetcode 第 387 场周赛 题解

100234. 在矩阵上写出字母 Y 所需的最少操作次数

简单题

class Solution {
public:
    vector<int> resultArray(vector<int> &nums) {
        int n = nums.size();
        vector<int> v1, v2;
        v1.emplace_back(nums[0]);
        v2.emplace_back(nums[1]);
        for (int i = 2; i < n; i++) {
            if (v1.back() > v2.back()) {
                v1.emplace_back(nums[i]);
            } else {
                v2.emplace_back(nums[i]);
            }
        }
        v1.insert(v1.end(), v2.begin(), v2.end());
        return v1;
    }
};

100237. 元素和小于等于 k 的子矩阵的数目

预处理+bfs剪枝

class Solution {
public:
    int countSubmatrices(vector<vector<int>> &grid, int k) {
        queue<pair<int, int>> q;
        int n = grid.size(), m = grid[0].size(), ans = 0;
        // 初始化
        int cal[n][m],vis[n][m];
        memset(vis,0,sizeof(vis));
        memset(cal,0,sizeof(cal));

        // 预处理
        cal[0][0] = grid[0][0];
        for (int j = 1; j < m; ++j) {
            cal[0][j] = grid[0][j] + cal[0][j - 1];
        }
        for (int i = 1; i < n; ++i) {
            int res = 0;
            for (int j = 0; j < m; ++j) {
                res += grid[i][j];
                cal[i][j] = res + cal[i - 1][j];
            }
        }

        // bfs
        q.emplace(0, 0);
        while (!q.empty()) {
            int x = q.front().first, y = q.front().second;
            q.pop();
            if (!vis[x][y] && cal[x][y] <= k) {
                vis[x][y] = 1;
                ++ans;
                if (x + 1 < n) q.emplace(x + 1, y);
                if (y + 1 < m) q.emplace(x, y + 1);
            }
        }
        return ans;
    }
};

100234. 在矩阵上写出字母 Y 所需的最少操作次数

模拟

class Solution {
public:
    int minimumOperationsToWriteY(vector<vector<int>> &grid) {
        int n = grid.size(), mid = grid.size() / 2;

        function<bool(int, int)> inY = [&](int x, int y) -> bool {
            if (x <= mid && y <= mid && x == y) return true;
            if (x < mid && y > mid && x + y == mid + mid) return true;
            if (y == mid && x > mid) return true;
            return false;
        };

        int cnt_Y[3], cnt_X[3];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (inY(i, j)) {
                    cnt_Y[grid[i][j]]++;
                }
                else cnt_X[grid[i][j]]++;
            }
        }

        int sum_Y = n + n / 2, sum_X = n * n - sum_Y, ans = n*n;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; ++j) {
                if (i == j) continue;
                ans = min(ans, sum_Y - cnt_Y[i] + sum_X - cnt_X[j]);
            }
        }
        return ans;
    }
};

100246. 将元素分配到两个数组中 II

离散化+树状数组(单点更新,区域查询)

class Solution {
public:
    struct Tree {
        int n;
        int c[100005];

        Tree(int n) : n(n) {
            memset(c, 0, sizeof(c));
        }

        int lowbit(int x) {
            return x & (-x);
        }

        void add(int x, int val) { //在x位置加上val(是变化量),单点更新
            while (x <= n) {
                c[x] += val;
                x += lowbit(x);
            }
        }

        int getSum(int x) { //求c[1 - i]的和,区间查询
            int res = 0;
            while (x) {
                res += c[x];
                x -= lowbit(x);
            }
            return res;
        }
    };

    vector<int> resultArray(vector<int> &nums) {
        int n = nums.size();
        vector<int> nums2(n), temp(nums);
        // 离散化
        // 排序
        sort(temp.begin(), temp.end());
        // 去重
        temp.erase(unique(temp.begin(), temp.end()), temp.end());
        for(int i:temp){
            cout<<i<<" ";
        }cout<<endl;
        //寻找nums中每个值在排序之后的下标,转化为nums2
        for (int i = 0; i < n; i++) {
            nums2[i] = lower_bound(temp.begin(), temp.end(), nums[i]) - temp.begin() + 1;
        }
        int len = temp.size();
        //开始按照题目要求进行模拟
        vector<int> v1, v2;
        v1.emplace_back(nums2[0]);
        v2.emplace_back(nums2[1]);
        Tree tree1(len + 1), tree2(len + 1);
        tree1.add(nums2[0], 1);
        tree2.add(nums2[1], 1);
        for (int i = 2; i < n; i++) {
            int n1 = v1.size(), n2 = v2.size();
            //总数减去小于等于的元素数目就是大于的元素数目
            int sum1 = n1 - tree1.getSum(nums2[i]), sum2 = n2 - tree2.getSum(nums2[i]);
            //按照规则分类
            if (sum1 > sum2 || (sum1 == sum2 && n1 <= n2)) {
                v1.emplace_back(nums2[i]);
                tree1.add(nums2[i], 1);
            } else {
                v2.emplace_back(nums2[i]);
                tree2.add(nums2[i], 1);
            }
        }
        v1.insert(v1.end(), v2.begin(), v2.end());
        for (int i: v1) {
            i = temp[i - 1];
        }
        return v1;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值