携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天,点击查看活动详情
第 308 场周赛
和有限的最长子序列
给你一个长度为 n 的整数数组 nums ,和一个长度为 m 的整数数组 queries 。
返回一个长度为 m 的数组 answer,其中 answer[i] 是 nums 中 元素之和小于等于 queries[i] 的 子序列 的 最大 长度 。
子序列 是由一个数组删除某些元素(也可以不删除)但不改变剩余元素顺序得到的一个数组。
示例 1:
输入: nums = [4,5,2,1], queries = [3,10,21]
输出: [2,3,4]
解释: queries 对应的 answer 如下:
- 子序列 [2,1] 的和小于或等于 3 。可以证明满足题目要求的子序列的最大长度是 2 ,所以 answer[0] = 2 。
- 子序列 [4,5,1] 的和小于或等于 10 。可以证明满足题目要求的子序列的最大长度是 3 ,所以 answer[1] = 3 。
- 子序列 [4,5,2,1] 的和小于或等于 21 。可以证明满足题目要求的子序列的最大长度是 4 ,所以 answer[2] = 4 。
示例 2:
输入: nums = [2,3,4,5], queries = [1]
输出: [0]
解释: 空子序列是唯一一个满足元素和小于或等于 1 的子序列,所以 answer[0] = 0 。
提示:
n == nums.lengthm == queries.length1 <= n, m <= 10001 <= nums[i], queries[i] <= 106
思路
他只要求子序列满足条件的最长长度,又不求是什么子序列
那我们就可以把子序列排个序
然后暴力循环求就可以了,
当然,若是数据量再大一点,我们可以使用二分来优化到
代码
class Solution {
public:
vector<int> answerQueries(vector<int>& nums, vector<int>& queries) {
sort(nums.begin(), nums.end());
vector<int> ans;
for (auto v : queries) {
int sum = 0, cnt = 0;
for (int i = 0; i < nums.size(); i ++) {
if (nums[i] + sum > v) break;
sum += nums[i];
cnt ++;
}
ans.push_back(cnt);
}
return ans;
}
};
从字符串中移除星号
给你一个包含若干星号 * 的字符串 s 。
在一步操作中,你可以:
- 选中
s中的一个星号。 - 移除星号 左侧 最近的那个 非星号 字符,并移除该星号自身。
返回移除 所有 星号之后的字符串 。
注意:
- 生成的输入保证总是可以执行题面中描述的操作。
- 可以证明结果字符串是唯一的。
示例 1:
输入: s = "leet**cod*e"
输出: "lecoe"
解释: 从左到右执行移除操作:
- 距离第 1 个星号最近的字符是 "leet**cod*e" 中的 't' ,s 变为 "lee*cod*e" 。
- 距离第 2 个星号最近的字符是 "lee*cod*e" 中的 'e' ,s 变为 "lecod*e" 。
- 距离第 3 个星号最近的字符是 "lecod*e" 中的 'd' ,s 变为 "lecoe" 。
不存在其他星号,返回 "lecoe" 。
示例 2:
输入: s = "erase*****"
输出: ""
解释: 整个字符串都会被移除,所以返回空字符串。
提示:
1 <= s.length <= 105s由小写英文字母和星号*组成s可以执行上述操作
思路
利用栈一样的结构来消除*抵消掉的东西
比第一题还简单
代码
class Solution {
public:
string removeStars(string s) {
string ans;
for (auto v : s) {
if (v == '*') {
if (ans.size()) ans.pop_back();
} else {
ans.push_back(v);
}
}
return ans;
}
};
收集垃圾的最少总时间
给你一个下标从 0 开始的字符串数组 garbage ,其中 garbage[i] 表示第 i 个房子的垃圾集合。garbage[i] 只包含字符 'M' ,'P' 和 'G' ,但可能包含多个相同字符,每个字符分别表示一单位的金属、纸和玻璃。垃圾车收拾 一 单位的任何一种垃圾都需要花费 1 分钟。
同时给你一个下标从 0 开始的整数数组 travel ,其中 travel[i] 是垃圾车从房子 i 行驶到房子 i + 1 需要的分钟数。
城市里总共有三辆垃圾车,分别收拾三种垃圾。每辆垃圾车都从房子 0 出发,按顺序 到达每一栋房子。但它们 不是必须 到达所有的房子。
任何时刻只有 一辆 垃圾车处在使用状态。当一辆垃圾车在行驶或者收拾垃圾的时候,另外两辆车 不能 做任何事情。
请你返回收拾完所有垃圾需要花费的 最少 总分钟数。
示例 1:
输入: garbage = ["G","P","GP","GG"], travel = [2,4,3]
输出: 21
解释:
收拾纸的垃圾车:
1. 从房子 0 行驶到房子 1
2. 收拾房子 1 的纸垃圾
3. 从房子 1 行驶到房子 2
4. 收拾房子 2 的纸垃圾
收拾纸的垃圾车总共花费 8 分钟收拾完所有的纸垃圾。
收拾玻璃的垃圾车:
1. 收拾房子 0 的玻璃垃圾
2. 从房子 0 行驶到房子 1
3. 从房子 1 行驶到房子 2
4. 收拾房子 2 的玻璃垃圾
5. 从房子 2 行驶到房子 3
6. 收拾房子 3 的玻璃垃圾
收拾玻璃的垃圾车总共花费 13 分钟收拾完所有的玻璃垃圾。
由于没有金属垃圾,收拾金属的垃圾车不需要花费任何时间。
所以总共花费 8 + 13 = 21 分钟收拾完所有垃圾。
示例 2:
输入: garbage = ["MMM","PGM","GP"], travel = [3,10]
输出: 37
解释:
收拾金属的垃圾车花费 7 分钟收拾完所有的金属垃圾。
收拾纸的垃圾车花费 15 分钟收拾完所有的纸垃圾。
收拾玻璃的垃圾车花费 15 分钟收拾完所有的玻璃垃圾。
总共花费 7 + 15 + 15 = 37 分钟收拾完所有的垃圾。
提示:
2 <= garbage.length <= 105garbage[i]只包含字母'M','P'和'G'。1 <= garbage[i].length <= 10travel.length == garbage.length - 11 <= travel[i] <= 100
思路
逆序往回找到第一个需要打扫的位置,然后开始累加计算
写一个函数封装一下这个过程,三次调用即可
代码
class Solution {
public:
int get(vector<string>& garbage, vector<int>& travel, char c) {
int f = 0, sum = 0;
for (int i = garbage.size() - 1; i > 0; i --) {
int siz = count(begin(garbage[i]), end(garbage[i]), c);
if (f == 0 && siz == 0) continue;
f = 1;
sum += siz;
sum += travel[i-1];
}
sum += count(begin(garbage[0]), end(garbage[0]), c);
return sum;
}
int garbageCollection(vector<string>& garbage, vector<int>& travel) {
int ans = 0;
ans += get(garbage, travel, 'M');
ans += get(garbage, travel, 'P');
ans += get(garbage, travel, 'G');
return ans;
}
};
给定条件下构造矩阵
给你一个 正 整数 k ,同时给你:
- 一个大小为
n的二维整数数组rowConditions,其中rowConditions[i] = [abovei, belowi]和 - 一个大小为
m的二维整数数组colConditions,其中colConditions[i] = [lefti, righti]。
两个数组里的整数都是 1 到 k 之间的数字。
你需要构造一个 k x k 的矩阵,1 到 k 每个数字需要 恰好出现一次 。剩余的数字都是 ****0 。
矩阵还需要满足以下条件:
- 对于所有
0到n - 1之间的下标i,数字abovei所在的 行 必须在数字belowi所在行的上面。 - 对于所有
0到m - 1之间的下标i,数字lefti所在的 列 必须在数字righti所在列的左边。
返回满足上述要求的 任意 矩阵。如果不存在答案,返回一个空的矩阵。
示例 1:
输入: k = 3, rowConditions = [[1,2],[3,2]], colConditions = [[2,1],[3,2]]
输出: [[3,0,0],[0,0,1],[0,2,0]]
解释: 上图为一个符合所有条件的矩阵。
行要求如下:
- 数字 1 在第 1 行,数字 2 在第 2 行,1 在 2 的上面。
- 数字 3 在第 0 行,数字 2 在第 2 行,3 在 2 的上面。
列要求如下:
- 数字 2 在第 1 列,数字 1 在第 2 列,2 在 1 的左边。
- 数字 3 在第 0 列,数字 2 在第 1 列,3 在 2 的左边。
注意,可能有多种正确的答案。
示例 2:
输入: k = 3, rowConditions = [[1,2],[2,3],[3,1],[2,3]], colConditions = [[2,1]]
输出: []
解释: 由前两个条件可以得到 3 在 1 的下面,但第三个条件是 3 在 1 的上面。
没有符合条件的矩阵存在,所以我们返回空矩阵。
提示:
2 <= k <= 4001 <= rowConditions.length, colConditions.length <= 104rowConditions[i].length == colConditions[i].length == 21 <= abovei, belowi, lefti, righti <= kabovei != belowilefti != righti
思路
首先我们要明确一个事情:有环的关系一定无解
为什么呢?显然,这个东西若是有环,关系就矛盾了 否则一定有解,为什么呢?
我们把x轴和y轴拆开看
我们发现,x和y轴是互不影响的
棋盘大小是 k * k的 这个就代表了我们是可以对于每一个棋子单独放一行一列的 所以他们是互不影响的。
只需要关心一下棋子之间的先后顺序
所以,解法就是 对于x和y轴分开讨论
对条件建图,跑拓扑排序分配行号和列号,同时判环
代码
class Solution {
public:
int get(int k, vector<vector<int>>& Conditions, vector<int>& ans) {
vector<vector<int>> ve(k, vector<int>());
vector<int> in(k);
queue<int> que;
int cnt = 0, idx = 0;
for (auto v : Conditions) ve[v[0]-1].push_back(v[1]-1), in[v[1]-1] ++;
for (int i = 0; i < k; i ++) if (!in[i]) que.push(i), ans[i] = idx ++;
while (que.size()) {
auto t = que.front(); que.pop();
cnt ++;
for (auto v : ve[t])
if (!--in[v]) que.push(v), ans[v] = idx ++;
}
if (cnt != k) return false;
return true;
}
vector<vector<int>> buildMatrix(int k, vector<vector<int>>& rowConditions, vector<vector<int>>& colConditions) {
vector<int> x(k), y(k);
int flag = 1;
flag = flag && get(k, rowConditions, x);
flag = flag && get(k, colConditions, y);
if (!flag) return {};
vector<vector<int>> ve(k, vector<int>(k));
for (int i = 0; i < k; i ++) ve[x[i]][y[i]] = i + 1;
return ve;
}
};