leetcode第387场周赛

本文介绍了三种与矩阵操作相关的算法:计算元素和小于等于k的子矩阵数目,使用二维前缀和;在矩阵上最少操作次数写出Y字母,以及将元素离散化并分配到两个数组中的方法。
摘要由CSDN通过智能技术生成

3070. 元素和小于等于 k 的子矩阵的数目3069. 将元素分配到两个数组中 I

根据题意模拟即可。

class Solution {
public:
    vector<int> resultArray(vector<int>& nums) {
        vector<int> a, b;
        int n = (int)nums.size();
        a.push_back(nums[0]);
        b.push_back(nums[1]);
        for (int i = 2; i < n; i++) {
            if (a.back() > b.back()) a.push_back(nums[i]);
            else b.push_back(nums[i]);
        }
        reverse(b.begin(), b.end());
        while (!b.empty()) a.push_back(b.back()),  b.pop_back();
        return a;
    }
};

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

统计属于Y字母区域的0,1,2的数量,再统计矩阵0,1,2的总数目,然后枚举Y型区域全为0,1,2,枚举矩形除Y型区域外全为0,1,2(两者不相等)。然后维护最小值即可。 

class Solution {
public:
    int minimumOperationsToWriteY(vector<vector<int>>& grid) {
        int ans = 1e9;
        //a维护矩形0,1,2的数目
        //b维护Y型区域0,1,2的数目
        vector<int> a(3, 0), b(3, 0);
        int n = grid.size();
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                a[grid[i][j]] += 1;
        int x = 0, y = 0;
        while (x <= n / 2 && y <= n / 2) b[grid[x][y]]++, x++, y++;
        x--,y--;
        while (y < n) b[grid[x][y]]++, x--,y++;
        x = n / 2, y = n / 2;
        while(x < n) b[grid[x][y]]++, x++;
        //最中间的矩形块多算了两遍 所以减2
        b[grid[n / 2][n / 2]] -= 2;
        //枚举Y型区域和矩形区域的数字是多少
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++)
                if (i != j) {
                    //Y型区域改成b[i]为:b[0] + b[1] + b[2] - b[i]
                    //矩形以外的区域改成a[j]为:a[0] + a[1] + a[2] - (b[0] + b[1] + b[2]) - (a[j] -  b[j])
                    //两者相加
                    ans = min(ans, - b[i] + a[0] + a[1] + a[2] - a[j] + b[j]);
                }
        }
        return ans;
    }
};

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

维护一个二维前缀和即可。但要注意有一部分贡献会加两遍,所以要减去。

class Solution {
public:
    int countSubmatrices(vector<vector<int>>& grid, int k) {
        int m = grid.size();
        int n = grid[0].size();
        int ans = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (i > 0) grid[i][j] += grid[i - 1][j];
                if (j > 0) grid[i][j] += grid[i][j - 1];
                if (i > 0 && j > 0) grid[i][j] -= grid[i - 1][j - 1];
                if (grid[i][j] <= k) ans++;
            }
        }
        return ans;
    }

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

只有10^5个数,但值的范围为1~10^9,所以考虑离散化。维护两个树状数组,用于查询两个arr数组中>x的数量是多少(树状数组查询的是<=x的数,我们维护一个总数量,两者相减就可以得到),然后根据题目题意所求即可。

class Solution {
public:
    const int N = 100001;
    //两个树状数组
    int c1[100010], c2[100010];
    int lowbit(int x) {return x &(-x);}
    int get_num1(int x)
    {
        int sum = 0;
        for(; x; x -= lowbit(x)) sum += c1[x];
        return sum;
    }
    int get_num2(int x)
    {
        int sum = 0;
        for(; x; x -= lowbit(x)) sum += c2[x];
        return sum;
    }
    void add1(int x)
    {
        for (; x < N; x += lowbit(x)) c1[x] += 1;
    }
    void add2(int x)
    {
        for (; x < N; x += lowbit(x)) c2[x] += 1;
    }
    vector<int> resultArray(vector<int>& nums) {
        //离散化 + 树状数组插入 + 查询
        int n = nums.size();
        vector<int> ans(n);
        //a:离散化数组
        vector<int> a;
        for (int i = 0; i < n; i++) a.push_back(nums[i]);
        sort(a.begin(), a.end());
        a.erase(unique(a.begin(), a.end()), a.end());
        //映射后查询下标
        auto find = [&](int x) 
        {
            int l = 0, r = a.size() - 1;
            while(l < r)
            {
                int mid = l + r  + 1>> 1;
                if(x >= a[mid]) l = mid;
                else r = mid - 1;
            }
            return r + 1;//从1开始 树状数组也是从1开始的
        };
        //用ans来记录答案
        int l = 0, r = n - 1;
        ans[l++] = nums[0], ans[r--] = nums[1];
        add1(find(nums[0])), add2(find(nums[1]));
        //记录两个数组的数目,刚开始两个数组的数目都为1
        int num1 = 1, num2 = 1;
        for (int i = 2; i < n; i++) {
            int x = find(nums[i]);
            int nums1 = get_num1(x), nums2 = get_num2(x);
            //cout << num1 << " " << nums1 << " " << num2 << " " << nums2 << endl;
            if (num1 - nums1 > num2 - nums2) { 
                num1++;
                ans[l++] = nums[i];
                add1(x);
            }
            else if (num1 - nums1 < num2 - nums2) {
                num2++;
                ans[r--] = nums[i];
                add2(x);
            }
            //两者>x的数量相等
            else {
                if (num1 > num2) {
                    num2++;
                    ans[r--] = nums[i];
                    add2(x);
                }
                else {
                    num1++;
                    ans[l++] = nums[i];
                    add1(x);
                }
            }
        }
        //注意拼接的话arr2数组需要翻转一下
        reverse(ans.begin() + l, ans.end());
        return ans;
    }
};

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值