Leetcode第309场周赛
第一题:2399. 检查相同字母间的距离
分析:用一个数组记录每个字符首次出现的位置并计算距离。定义一个26位场的vector数组,每位的初始值为-1,遍历数组,某个字符第一次出现时就将其值vec[c]变为i作为第一次出现的位置,如果不是第一次出现就用此时的i减去该字符第一次出现记录的位置减一,得出来的就是两相同字符间的距离。
代码:
class Solution {
public:
bool checkDistances(string s, vector<int>& distance) {
int n = s.size();
vector<int> vec(26, -1);
for (int i = 0; i < n; i++) {
int c = s[i] - 'a';
// 字母第一次出现,记录位置
if (vec[c] == -1) vec[c] = i;
// 字母第二次出现,计算距离
else vec[c] = i - vec[c] - 1;
}
// 与 distance 比较
for (int i = 0; i < 26; i++) if (vec[i] >= 0 && vec[i] != distance[i]) return false;
return true;
}
};
分析:利用数学方法,记从起点startPos到终点endPos的方向为正方向,从起点到终点一共需要往正方向走a步,往负方向走k步,易得a - (k - a) = d,d为startPos到endPos的距离。判断d+k是否为偶数,然后用递归计算组合数。思路参考
代码:
class Solution {
const int MOD = 1000000007;
public:
int numberOfWays(int startPos, int endPos, int K) {
int d = abs(startPos - endPos);
if ((d + K) % 2 == 1 || d > K) return 0;
// 递推求组合数
vector<vector<long long>> f;
f.resize(K + 1, vector<long long>(K + 1));
for (int i = 0; i <= K; i++) {
f[i][0] = 1;
for (int j = 1; j <= i; j++) f[i][j] = (f[i - 1][j] + f[i - 1][j - 1]) % MOD;
}
return f[K][(d + K) / 2];
}
};
Acwing第67场周赛
第一题:4609. 火柴棍数字
分析:经过分析可知,当火柴根数小于3时只能输出1,当火柴根数为偶数时,每一位都是1是所组成的数字位数越长,也就越大;当火柴根数为奇数时,第一位为7,后面每位都是1时所组成的数数字越长,也就是越大。
代码:
#include<iostream>
using namespace std;
int main(){
int n,x;
cin >> n;
while(n --){
cin >> x;
if(x < 3)cout << 1 << endl;
else if(x % 2 == 0){
for(int i = x/2;i > 0;i --)cout << 1;
cout << endl;
}
else{
cout << 7;
for(int i = x/2 - 1;i > 0;i --)cout << 1;
cout << endl;
}
}
return 0;
}
第二题:4610. 列表排序
分析:暴力枚举思路。由于只能交换一次列,那么我们首先枚举出交换列的所有情况。时间复杂度m×m在此基础上判断每一行和[1,2,3,4…,m]有多少个数不同,分析可知如果超过2个,则这种情形不合法,返回NO,否则返回YES,总的时间复杂度为m×m×n。
代码:
int main()
{
cin >> n >> m;
for(int i = 0; i < n; i ++ ) {
for(int j = 0; j < m; j ++ ) {
cin >> s[i][j];
}
}
for(int i = 0; i < m; i ++ ) {
for(int j = i; j < m; j ++ ) {
for(int k = 0; k < n; k ++ ) swap(s[k][i], s[k][j]);
if(check()) {
puts("YES");
return 0;
}
for(int k = 0; k < n; k ++ ) swap(s[k][i], s[k][j]);
}
}
puts("NO");
return 0;
}