leetcode 第 196 场周赛

第一次参加力扣的比赛,结果给忘记了,想起来的时候快结束了,只做了两个题,可惜可惜。

题目A 判断能否形成等差数列

给你一个数字数组 arr 。
如果一个数列中,任意相邻两项的差总等于同一个常数,那么这个数列就称为 等差数列 。
如果可以重新排列数组形成等差数列,请返回 true ;否则,返回 false 。

题解

排序:
对数组sort一下,求出公差,for一边判断一下。
不排序:
遍历一遍,记录MAX和MIN,并hash一下记录出现的元素,然后通过MAX,MIN,size求出公差,然后判断等差数列所以元素是否存在。

代码

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

题目B 所有蚂蚁掉下来前的最后一刻

有一块木板,长度为 n 个 单位 。一些蚂蚁在木板上移动,每只蚂蚁都以 每秒一个单位 的速度移动。其中,一部分蚂蚁向 左 移动,其他蚂蚁向 右 移动。
当两只向 不同 方向移动的蚂蚁在某个点相遇时,它们会同时改变移动方向并继续移动。假设更改方向不会花费任何额外时间。
而当蚂蚁在某一时刻 t 到达木板的一端时,它立即从木板上掉下来。
给你一个整数 n 和两个整数数组 left 以及 right 。两个数组分别标识向左或者向右移动的蚂蚁在 t = 0 时的位置。请你返回最后一只蚂蚁从木板上掉下来的时刻。

题解

思维题,只需要把改变方向的两个蚂蚁想成交换一下,就相当于蚂蚁一直向前走,距离所在方向端点最远的蚂蚁就是答案。

代码

class Solution {
public:
    int getLastMoment(int n, vector<int>& left, vector<int>& right) {
        int ans = 0;
        for(int i = 0;i < left.size();i++){
            ans = max(ans,left[i]);
        }
        for(int i = 0;i < right.size();i++){
            ans = max(ans,n-right[i]);
        }
        return ans;
    }
};

题目B 统计全 1 子矩形

给你一个只包含 0 和 1 的 rows * columns 矩阵 mat ,请你返回有多少个 子矩形 的元素全部都是 1 。

题解

暴力:
只需要预处理一下每个点向左连续为1的个数,枚举每个点做矩阵右下点时,高度为k的矩阵个数(k行内最短的连续1的个数)
时间复杂度O(nnm)

代码

//暴力
class Solution {
public:
    int numSubmat(vector<vector<int>>& mat) {
        int n = mat.size();
        int m = mat[0].size();
        vector<vector<int> > count(n,vector<int>(m));
        for(int i = 0;i < n;i++){
            if(mat[i][0] == 1) count[i][0] = 1;
            else count[i][0] = 0;
            for(int j = 1;j < m;j++){
                if(mat[i][j]) count[i][j] = count[i][j-1]+1;
                else count[i][j] = 0;
            }
        }
        int ans = 0;
        for(int i = 0;i < n;i++){
            for(int j = 0;j < m;j++){
                int sum = INT_MAX;
                for(int k = i;k >= 0;k--){
                    sum = min(sum,count[k][j]);
                    ans += sum;
                }
            }
        }
        return ans;
    }
};

题目D 5455. 最多 K 次交换相邻数位后得到的最小整数

给你一个字符串 num 和一个整数 k 。其中,num 表示一个很大的整数,字符串中的每个字符依次对应整数上的各个 数位 。
你可以交换这个整数相邻数位的数字 最多 k 次。
请你返回你能得到的最小整数,并以字符串形式返回。

题解

首先,整数大小依据是最高位的数字大小,所以,最优解一定是尽量把最高位变小, 我们从最高位的数字,首先从最小数0开始枚举是否可以通过交换置换到当前位置(最近的0的位置 - 空位 < 交换次数),不可以一次枚举12.9。
我们要计算当前位置交换到目标位置需要的次数,需要记录这段范围内空闲的位置,明显线段树(只有单点修改,区间查询,我就只写了树状数组)

代码

#include 
using namespace std;
const int MAXN = 3e4 + 50;
vector<int> pos[10];
int sum[MAXN], cur[10], n;

int lowbit(int x){ 
    return x & -x; 
}
void add(int x, int v){
    for (int i = x; i <= n; i += lowbit(i)) 
        sum[i] += v;
}
int get(int x){
    int ret = 0;
    for (int i = x; i; i -= lowbit(i)) 
        ret += sum[i];
    return ret;
}

class Solution {
public:
    string minInteger(string num, int K) {
        n = num.length();

        for (int i = 0; i <= n; i++) 
            sum[i] = 0;
        for (int i = 0; i < 10; i++) 
            pos[i].clear(), cur[i] = 0;
        for (int i = 0; i < n; i++) 
            pos[num[i] - '0'].push_back(i + 1);

        string ans = "";
        for (int i = 1; i <= n; i++){
            for (int k = 0; k < 10; k++){
                if (cur[k] >= pos[k].size()) continue;
                int op = pos[k][cur[k]];
                int p = op + get(op) - 1;
                if (p <= K){
                    K -= p;
                    ans += (char)('0' + k);
                    add(op, -1);
                    cur[k]++;
                    break;
                }
            }
        }

        return ans;
    }
};

你可能感兴趣的:(leetcode)