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
考虑到存在数位偏移的情况,可使用树状数组+差分进行优化。
代码
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;
}
};