大家都好厉害,手速都快的飞起。最近几场比赛,罚时四十分钟很难进前到一百了,真的是太"卷"了哈哈哈。
5976. 检查是否每一行每一列都包含全部整数
思路:哈希数组
时间复杂度:
空间复杂度:
因为 ,所以「包含全部整数」和「无重复数字」是等价的。因此,只需检查每行每列中是否有重复数字即可。
class Solution {
public:
bool checkValid(vector<vector<int>>& matrix) {
// 检查过程中的标记数据
bool mark[101] = {0};
int n = matrix.size();
for (int i = 0; i < n; i++) {
// 检查第 i 行
memset(mark, 0, sizeof(mark));
for (int j = 0; j < n; j++) {
if (mark[matrix[i][j]]) { return false; }
mark[matrix[i][j]] = true;
}
// 检查第 i 列
memset(mark, 0, sizeof(mark));
for (int j = 0; j < n; j++) {
if (mark[matrix[j][i]]) { return false; }
mark[matrix[j][i]] = true;
}
}
return true;
}
};
5977. 最少交换次数来组合所有的 1 II
思路:区间求和
时间复杂度:
空间复杂度:
设数组中总共有 count 个 1。设有长度为 count 的区间 ,其中有 个 1。若使此区间全部为 1,则必须移动 次。
枚举区间的起始位置 ,计算对应的 ,最小的 即为答案。其中, 的计算可用前缀和实现,环形数组可用两份拼接的 解决。
class Solution {
public:
int minSwaps(vector<int>& nums) {
vector<int> data;
// 写入两份 nums 至 data 中,便于处理环的情形
// 前后各插入一个 0,便于处理边界情形。
data.emplace_back(0);
data.insert(data.end(), nums.begin(), nums.end());
data.insert(data.end(), nums.begin(), nums.end());
data.emplace_back(0);
// 统计 1 的个数
int n = nums.size();
int count = 0;
for (int i = 0; i < n; i++) {
count += nums[i];
}
if (count == 0) {
return 0;
}
// 处理前缀和和后缀和
n = data.size();
vector<int> pre = data;
for (int i = 1; i < n; i++) {
pre[i] = pre[i-1] + data[i];
}
vector<int> suf = data;
for (int i = n-2; i >= 0; i--) {
suf[i] = suf[i+1] + data[i];
}
// 枚举最终全是 1 的区间的位置,利用 pre 和 suf 计算对应的移动次数。
int anw = n;
for (int i = 1; i+1 < n; i++) {
if (i - count > 0) {
anw = min(anw, count - (pre[i] - pre[i-count]));
}
if (i + count < n) {
anw = min(anw, count - (suf[i] - suf[i+count]));
}
}
return anw;
}
};
5978. 统计追加字母可以获得的单词数
思路:预处理,哈希
时间复杂度:, 为字符串长度上限
空间复杂度:
如果 可由 转换得到,则 添加一个字符 后,必然和 的字符种类和数量完全一致。
因此,可先预处理出所有 追加一个字符能得到的单词。因为只关心字符的种类和数量,而非顺序,因此可将这些单词按字典序排序,然后将排序的单词写入哈希表。
比如字符串 追加字符后可得到 ,,...,,然后对每个单词排序,,,...,,然后写入哈希表。
接下来,遍历 ,依然对每个单词排序,若排序的 存在于哈希表中,则可转换得到,反之则不能。
class Solution {
public:
int wordCount(vector<string>& startWords, vector<string>& targetWords) {
// 哈希表
unordered_set<std::string> mark;
for (const auto &word : startWords) {
bool hash[26] = {0};
for (auto c : word) {
hash[c-'a'] = true;
}
for (int i = 0; i < 26; i++) {
if (hash[i] == false) {
// 追加不存在的字符
char c = i + 'a';
auto tmp = word + c;
// 排序
sort(tmp.begin(), tmp.end());
// 写入哈希表
mark.insert(tmp);
}
}
}
int cnt = 0;
for (auto w : targetWords) {
// 排序
sort(w.begin(), w.end());
// 查哈希表
cnt += mark.count(w);
}
return cnt;
}
};
5979. 全部开花的最早一天
思路:二分
时间复杂度:
空间复杂度:
设全部开花的最早一天为 ,则 之前不可能全部开花,不然就与 相悖。另外, 之后也必然是全部开花的。因此可用二分确定 的值。
则问题转化为:给定 X,如何判断其能否全部开花。
考虑第 种花,若其在第 天盛开,则必然要在 之前种下。因此,可将 按照 升序排序。如果排序后的 均满足:
则 X 满足要求,反之则必然不可。
class Solution {
public:
bool check(int X, const vector<pair<int, int>>& data) {
// sum 计算 plant 的前缀和
int64_t sum = 0;
for (auto p : data) {
sum += p.second;
// 检查 X - grow[i] 之前是否有时间种完前 i 种植物
if (sum >= X - p.first) {
return false;
}
}
return true;
}
int earliestFullBloom(vector<int>& plantTime, vector<int>& growTime) {
std::vector<pair<int, int>> data;
int n = plantTime.size();
// 先按 grow 降序,这样后面可 O(n) 的得到 X - grow[i] 和 plant[i]
for (int i = 0; i < n; i++) {
data.emplace_back(growTime[i], plantTime[i]);
}
sort(data.begin(), data.end(), [](const auto &lhs, const auto &rhs) {
return lhs.first > rhs.first;
});
//开始二分
int64_t L = 1, R = n * 20000L;
while (L <= R) {
int X = (L+R)/2;
if (check(X, data)) {
R = X-1;
} else {
L = X+1;
}
}
return L-1;
}
};