本文同步发布于 个人博客
前言
这场打得就很辣鸡了,因为 B 题我看错题了!
不过 wls 登顶了Orz
A 2133. 检查是否每一行每一列都包含全部整数
题意
给出
n
×
n
n\times n
n×n 的矩阵,判断每一行和每一列是否包含了
[
1
,
n
]
[1,n]
[1,n] 中的所有整数。
1
≤
n
≤
100
1\le n\le 100
1≤n≤100。
分析
用个
s
e
t
set
set 维护即可。
复杂度是
O
(
n
2
l
o
g
n
)
O(n^2logn)
O(n2logn)。
代码
class Solution {
public:
bool checkValid(vector<vector<int>>& matrix) {
int n = matrix.size();
for(int i = 0; i < n; i++){
set<int> s;
for(int j = 0; j < n; j++) s.insert(matrix[i][j]);
if(s.size() != n) return 0;
s.clear();
for(int j = 0; j < n; j++) s.insert(matrix[j][i]);
if(s.size() != n) return 0;
}
return 1;
}
};
B 2134. 最少交换次数来组合所有的 1
题意
给出长度为 n n n 的环形 01 01 01 数组,每次可以交换 任意 两个位置的数,问最少的交换次数,使得所有的 1 1 1 聚在一起。
1 ≤ n ≤ 1 0 5 1\le n\le 10^5 1≤n≤105
分析
我太sb了,以为是交换相邻的两个元素,导致这题非常难做,发现大家都会的时候我都懵逼了=.=。
如果是任意交换的话,我们设 1 1 1 的总个数为 t o t tot tot,然后可以枚举环形数组的起点 p p p(一定以某个 1 1 1 作为起点),然后求 [ p , p + t o t − 1 ] [p,p+tot-1] [p,p+tot−1] 中 0 0 0 的个数的最小值即可(因为每次一定是把这段区间一个 0 0 0 替换成 1 1 1)。要注意特判全部都是 0 0 0 的情况。
时间复杂度为 O ( n ) O(n) O(n)。
代码
class Solution {
public:
int minSwaps(vector<int>& nums) {
int n = nums.size(), ans = 1e9, tot = 0;
for(int i = 0; i < n; i++) nums.push_back(nums[i]), tot += nums[i];
vector<int> sum(n * 2);
sum[0] = 1 - nums[0];
for(int i = 1; i < nums.size(); i++) sum[i] = sum[i - 1] + 1 - nums[i];
auto cal = [&](int l, int r){
return sum[r] - (l > 0? sum[l - 1]: 0);
};
for(int i = 0; i < n; i++){
if(nums[i] == 1){
ans = min(ans, cal(i, i + tot - 1));
}
}
if(!tot) ans = 0;
return ans;
}
};
C 2135. 统计追加字母可以获得的单词数
题意
有 n n n 个初始单词, m m m 个目标单词,问有多少个目标单词能否通过某个初始单词添加一个字母之后重排列得到。
1 ≤ n , m ≤ 5 × 1 0 4 , 1 ≤ l e n g t h ≤ 26 1\le n,m\le 5\times 10^4,1\le length\le 26 1≤n,m≤5×104,1≤length≤26。
分析
先将初始单词和目标单词都从小到大排序,然后枚举目标单词中添加的字母,判断剩下的字母组合起来的单词是否在初始单词里面即可,可以用 std::map 来实现。
时间复杂度 O ( m ∣ s ∣ l o g ∣ s ∣ ) O(m|s|log|s|) O(m∣s∣log∣s∣)。
代码
class Solution {
public:
int wordCount(vector<string>& startWords, vector<string>& targetWords) {
for(auto& e: startWords) sort(e.begin(), e.end());
for(auto& e: targetWords) sort(e.begin(), e.end());
auto s = startWords, t = targetWords;
map<string, int> mp;
for(auto& e: s) mp[e] = 1;
int ans = 0;
for(auto& e: t){
int n = e.size(), ok = 0;
for(int i = 0; i < n; i++){
string w = e.substr(0, i) + e.substr(i + 1, n - i - 1);
if(mp[w]) ok = 1;
}
ans += ok;
}
return ans;
}
};
D 2136. 全部开花的最早一天
题意
有 n n n 朵花,每朵花需要 p i p_i pi 的种植时间,种植完需要 g i g_i gi 的开花时间。问合理安排种花时间下所有花开花的最短时间。
1 ≤ n ≤ 1 0 5 , 1 ≤ p i , g i ≤ 1 0 4 1\le n\le 10^5,1\le p_i,g_i\le 10^4 1≤n≤105,1≤pi,gi≤104。
分析
首先所有花一定是连续种植的,不种白不种。
然后总时间一定取决于最后一朵花的时间 T = ∑ p i + g n T=\sum{p_i}+g_n T=∑pi+gn。因此我们让最后一朵花的 g g g 最小,即变成一个子问题。由数学归纳法可以得到,按照 g g g 从大到小排序可以使得总时间最小。
代码
class Solution {
public:
int earliestFullBloom(vector<int>& plantTime, vector<int>& growTime) {
int n = plantTime.size();
vector<int> id(n);
iota(id.begin(), id.end(), 0);
sort(id.begin(), id.end(), [&](int l, int r){
return growTime[l] > growTime[r];
});
int p = 0, ans = 0;
for(int i: id){
p += plantTime[i];
ans = max(ans, p + growTime[i]);
}
return ans;
}
};