这次差两分钟做出最后一道题
第308场周赛
2389. 和有限的最长子序列
我用的双重循环,时间复杂度挺高的,但是蛮有意思的哈哈哈
class Solution {
public:
vector<int> answerQueries(vector<int>& nums, vector<int>& query) {
vector<int> ans;
sort(nums.begin(), nums.end());
for(auto val : query){
int st = 0, sum = 0, res = 0;
for(int i = 0; i < nums.size(); i++){
sum += nums[i];
while(sum > val){
sum -= nums[st];
++st;
}
res = max(res, i - st + 1);
}
ans.push_back(res);
}
return ans;
}
};
(贪心,前缀和,二分) \(O((n+m)logn)\)
-
显然选择的数字越小最终的子集和也就会尽可能小。
-
可以先把 nums 数组从小到大排序,然后对于每个询问 qq,二分查找第一个大于 qq 的前缀和位置 pp 作为答案。
时间复杂度
- 排序的时间复杂度为 O(nlogn)。
- 排序后,每个询问二分的时间复杂度为 O(logn)。
- 故总时间复杂度为 O((n+m)logn)。
空间复杂度
需要 O(m+logn)的额外空间存储答案以及排序的递归系统栈。
class Solution {
public:
vector<int> answerQueries(vector<int>& nums, vector<int>& queries) {
const int n = nums.size();
sort(nums.begin(), nums.end());
for (int i = 1; i < n; i++)
nums[i] += nums[i - 1];
vector<int> ans;
for (int q : queries)
ans.push_back(upper_bound(nums.begin(), nums.end(), q) - nums.begin());
return ans;
}
};
2390. 从字符串中移除星号
使用栈进行模拟,遇到*
出栈,其他的进栈
时间复杂度
字符串扫描一遍,时间复杂度\(O(N)\)
空间复杂度
需要额外的和s一样长的空间,时间复杂度是\(O(N)\)
代码
const int N = 1e5 + 10;
char s[N];
class Solution {
public:
string removeStars(string str) {
int top = -1;
for(char &c : str){
if(c == '*') --top;
else s[++top] = c;
}
string ans = "";
for(int i = 0; i <= top; i++)
ans += s[i];
return ans;
}
};
2391. 收集垃圾的最少总时间
(模拟) O(nL)
- 答案可以拆分成所有房子的垃圾数量总和,再加上每辆垃圾车行驶到的最后一个房子的距离。
- 遍历所有房子的垃圾,找到每种垃圾最后出现的房子的位置。
时间复杂度
遍历所有房子的垃圾,故时间复杂度为 O(nL)
空间复杂度
仅需要常数的额外空间。
class Solution {
public:
int garbageCollection(vector<string>& gar, vector<int>& tra) {
int n = gar.size();
int ans = 0, metal_far = 0, paper_far = 0, glass_far = 0;
for(int i = 0; i < n; i++){
ans += gar[i].size();
for(auto c : gar[i]){
if(c == 'M') metal_far = i;
else if(c == 'P') paper_far = i;
else glass_far = i;
}
}
for(int i = 1; i < n - 1; i++) tra[i] += tra[i - 1];
if(metal_far > 0) ans += tra[metal_far - 1];
if(paper_far > 0) ans += tra[paper_far - 1];
if(glass_far > 0) ans += tra[glass_far - 1];
return ans;
}
};
2392. 给定条件下构造矩阵
(拓扑排序) O(k+m)
- 分别对行和列进行拓扑排序,求出每个数字所在的排名。
- 如果拓扑排序不存在,则说明答案不存在。
- 按照行和列的排名填充最终的矩阵。
时间复杂度
两次拓扑排序的时间复杂度为 O(k+m),其中 m 为条件的长度。
填充答案仅需要 O(k) 的时间。(忽略新建 \(k^2\) 零矩阵的时间。)
空间复杂度
需要 \(O(k^2)\) 的额外空间存储拓扑排序的数据结构和答案。
class Solution {
public:
vector<int> topSort(int k, vector<vector<int>>& condition){
vector<vector<int>> son(k + 1);
vector<int> in(k + 1);
for(auto &c : condition){
int a = c[0], b = c[1];
son[a].push_back(b);
++in[b];
}
vector<int> q(410);
int hh = 0, tt = -1;
for(int i = 1; i <= k; i++)
if(!in[i])
q[++tt] = i;
while(hh <= tt){
int t = q[hh++];
for(int u : son[t])
if(!--in[u])
q[++tt] = u;
}
if(tt != k - 1) return {};
return q;
}
int get(vector<int> &w, int t){
for(int i = 0; i < w.size(); i++)
if(w[i] == t)
return i;
return 0;
}
vector<vector<int>> buildMatrix(int k, vector<vector<int>>& row, vector<vector<int>>& col) {
auto r = topSort(k, row), c = topSort(k, col);
if(r.size() < k || c.size() < k) return {};
vector<vector<int>> ans(k, vector<int>(k));
for(int i = 1; i <= k; i++)
ans[get(r, i)][get(c, i)] = i;
return ans;
}
};