LeetCode第196场周赛题解

2020.7.5第196场周赛

1502. 判断能否形成等差数列

题意解读

判断一个给定的数列能否形成一个等差数列。

思路

先将给定的数列排序,判断每两个相邻的数的差值是否相等即可。

代码

class Solution {
public:
    bool canMakeArithmeticProgression(vector<int>& arr) {
        sort(arr.begin(), arr.end());
        int d = arr[1] - arr[0];
        for (int i = 1; i < arr.size(); i ++ )
        {
            if (arr[i] - arr[i - 1] != d) return false;
        }
        return true;
    }
};

1503. 所有蚂蚁掉下来前的最后一刻

题意解读

给定两个数组,分别表示向左走和向右走的蚂蚁的初始位置,n为木板的总长度,两只蚂蚁相遇时会改变方向,计算最后一只蚂蚁从木板上掉下来的时刻。

思路

两只蚂蚁相遇可以看作是两只蚂蚁穿过对方,不影响最后的结果,这样就只用计算距离左端点和右端点最远的蚂蚁掉下所需的时间了,没有向左或向右的蚂蚁时需要特判一下。
思路来源:蓝桥杯蚂蚁感冒

代码

class Solution {
public:
    int getLastMoment(int n, vector<int>& left, vector<int>& right) {
        sort(left.begin(), left.end());
        sort(right.begin(), right.end());
        int a, b;
        a = b = 0;
        if (left.size() != 0)
            a = left[left.size() - 1];
        if (right.size() != 0)
            b = n - right[0];
        int ans = max(a, b);
        return ans;
    }
};

1504. 统计全 1 子矩形

题意解读

给定一个由0和1组成的二维数组,统计其子矩阵中全部为1的数目.

思路

比赛时用的是二维前缀和的方法,利用矩形的左上角和右下角固定一个矩形,如果矩形的面积(即矩形内所有小正方形的数量)和矩形内的数字和相等,说明是符合条件的矩形,然后判断所有子矩形是否符合。
时间复杂度是O(n4)很慢很慢,但是能过

代码

class Solution {
public:
    int numSubmat(vector<vector<int>>& mat) {
        int a[155][155] = {0}, n, m;
        n = mat.size();
        m = mat[0].size();
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= m; j ++ )
            {
                a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + mat[i - 1][j - 1];
            }
        int ans = 0;
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= m; j ++ )
                for (int x = i; x <= n; x ++ )
                    for (int y = j; y <= m; y ++ )
                    {
                        int k = a[x][y] - a[i - 1][y] - a[x][j - 1] + a[i - 1][j - 1];
                        if (k == (x - i + 1) * (y - j + 1)) ans ++ ;
                    }
        return ans;
    }
};

1505. 最多 K 次交换相邻数位后得到的最小整数

题意解读

给定一个字符串,每次可以交换相邻两个数,求出最多经过k次交换的数的最小值。(可以含有前导零)

思路

要想使最后得到的数最小,需要依次从最高位到最低位满足能够取到的该数位上的最小值。
举例: 给定字符串4321,k = 4,首先看千位最小能取几,观察后发现个位上的1经过3次交换后可满足,此时将其他的数位上的数向后移动;再看到百位,此时只剩下一次机会,只能将4与3交换,故得到的最小值为1342

1342
1432
4321

考虑到存在数位偏移的情况,可使用树状数组+差分进行优化。

代码

class Solution {
public:
    vector<int> tr;
    int n;

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

    void add(int a, int b) {
        for (int i = a; i <= n; i += lowbit(i)) {
            tr[i] += b;
        }
    }

    int get_sum(int x) {
        int res = 0;
        for (int i = x; i; i -= lowbit(i)) {
            res += tr[i];
        }
        return res;
    }

    string minInteger(string num, int k) {
        n = num.size();
        tr.resize(n + 1); //树状数组从下标为1开始,故大小为n + 1
        queue<int> q[10];
        string res;
        num = ' ' + num; //字符串也从下标为1开始

        for (int i = 1; i <= n; i ++ ) //将所有数位的数的下标记录到队列中
            q[num[i] - '0'].push(i);

        for (int i = 1; i <= n; i ++ ) {
            for (int j = 0; j <= 9; j ++ ) {
                if (q[j].size()) {
                    int t = q[j].front(); 
                    //取出队头的初始下标(即下标最小值,此时的代价最小)
                    int pos = t + get_sum(t);
                    //计算偏移后的下标
                    if (pos - i <= k) { 
                    //和当前数位相隔小于等于k时可以移动
                        k -= pos - i;
                        res += j + '0'; //记录答案
                        q[j].pop(); //已用过的出队
                        add(1, 1);
                        add(t, -1); //利用差分更新偏移量
                        break;
                    }
                }
            }
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值