周赛链接:https://leetcode.cn/contest/weekly-contest-373/
100139. 循环移位后的矩阵相似检查
不需要判断奇数还是偶数,题目要求最后两个矩阵是否相同,那么向左循环移动和向右循环移动意义是一样的
奇数行右移k次,$$a[i]==a[(i + k) % size]$$
偶数行左移k次,$$a[i] == a[(i - k) % size]$$
向右循环移动即可,如果某个位置不相同,直接返回false
class Solution {
public:
bool areSimilar(vector<vector<int>>& mat, int k) {
bool flag = true;
for (auto row : mat) {
for (int i = 0; i < row.size(); i ++) {
if (row[i] != row[(i + k) % row.size()]) {
return false;
}
}
}
return flag;
}
};
100142. 交换得到字典序最小的数组
模拟,找规律,找联系。
对于每个数字,如果存在另外一个数字,跟他相差,小于等于limit,那么就是一个连通块,这样就能互相交换。
把nums排序后,需要找到一个最长的连续段,相邻数字的差是 <= limit
这一整段对应的下标集合,这些位置之间是可以随意排序的。
本题用到一个经典结论。
把序列中的每个元素看成图中的一个点,如果两个元素可以相互交换,则在两个元素之间连一条边。结论:处于同一连通块内的所有元素可以通过若干次操作排成任意顺序。
排序
把原序列,从小到大排好序,为了让答案的字典序最小,每个子段从小到大排序即可。
参考题解
class Solution {
public:
vector<int> lexicographicallySmallestArray(vector<int>& nums, int limit) {
int n = nums.size();
typedef pair<int, int> pii;
// 把所有元素从小到大排序,要记录一下原来的下标
vector<pii> vec;
for (int i = 0; i < n; i ++) vec.push_back(pii(nums[i], i));
sort(vec.begin(), vec.end());
// for (auto x : vec) {
// cout << x.first << ' ';
// }
// cout << endl;
// 把所有元素切成若干子段,子段内的相邻元素之差不超过 limit
/**
* segs 二维数组
**/
vector<vector<pii>> segs;
int last = -limit;
for (int i = 0; i < n; i ++) {
if (vec[i].first - last > limit) segs.push_back({}); // 这里插入一个空行,切割
segs.back().push_back(vec[i]);
last = vec[i].first; // 更新
}
vector<int> ans(n);
// 对每个子段分别从小到大排序,填回序列中
for (auto &seg : segs) {
vector<int> pos; // 每次新建一个数组,保存当前这层的下标
for (auto &p : seg) pos.push_back(p.second); // 把每一组的下标保存好
sort(pos.begin(), pos.end()); // seg 里面,每个组都是有序的,这里把下标排好序,让每个分组都可以互相插入进去
// 这样整体字典序就最小了
// for (auto x : pos) {
// cout << x << ' ';
// }
// cout << endl;
for (int i = 0; i < seg.size(); i ++) ans[pos[i]] = seg[i].first;
}
return ans;
}
};
100134. 统计美丽子字符串 I
100132. 统计美丽子字符串 II
参考题解:
class Solution {
public:
long long beautifulSubstrings(string s, int K) {
// 判断字符 c 是不是元音
auto check = [&](char c) {
return c == 'a' || c == 'e' || c == 'i' || c == 'o'
|| c == 'u';
};
int n = s.size();
// valid 里保存所有满足 w^2 mod k = 0 的 w,这里是暴力枚举。
vector<int> valid;
for (int rem = 0; rem < K; rem ++) {
if (rem * rem % K == 0) valid.push_back(rem);
}
long long ans = 0;
unordered_map<int, unordered_map<int ,int>> mp;
// 用长度为 0 的前缀初始化哈希表
mp[0][0] = 1;
// det: 前缀中元音 - 辅音的值
// cnt: 前缀中元音的数量
int det = 0, cnt = 0;
// 枚举子串右端点
for (int i = 0; i < n;i ++) {
if (check(s[i])) det ++, cnt ++;
else det --;
// 枚举 w
for (int rem : valid) {
int t = (cnt - rem + K) % K;
if (mp[det].count(t)) ans += mp[det][t];
}
// 用以 i 为结尾的前缀更新hash表
mp[det][cnt % K] ++;
}
return ans;
}
};
标签:周赛,int,det,++,vector,vec,rem,373,Leetcode
From: https://www.cnblogs.com/lukelmouse/p/17857687.html