T1:和有限的最长子序列
给你一个长度为 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 。
一开始看到子序列三个字就觉得不能先排序再解决问题。但是其实题目要求的只是子序列的长度,没有要求这个子序列,所以顺序其实就是可以打乱的了。所以可以先将nums数组排序,求出前缀和,这样找和小于等于quteries[i]的时候就可以用二分的方法进行查找。相当于把问题变成了二分查找问题。
class Solution {
public:
vector<int> answerQueries(vector<int>& nums, vector<int>& queries) {
int n = queries.size();
int m = nums.size();
sort(nums.begin(),nums.end());
vector<int>answer(n);
vector<int>presum(m);
presum[0]=nums[0];
for(int i = 1 ; i< m;i++){
presum[i] = presum[i-1]+nums[i];
}
for(int i = 0 ;i < n;i++){
int x = queries[i];
int pos =-1;
int left = 0 , right = m-1;
while (left <= right) {
int mid = (left + right) / 2;
if (presum[mid] <= x) {
pos = mid;
left = mid + 1;
}else {
right = mid - 1;
}
}
answer[i] = pos == -1 ? 0 : pos + 1;
}
return answer;
}
};
T2:从字符串中移除星号
给你一个包含若干星号 * 的字符串 s 。
在一步操作中,你可以:
选中 s 中的一个星号。
移除星号 左侧 最近的那个 非星号 字符,并移除该星号自身。
返回移除 所有 星号之后的字符串。
注意:
生成的输入保证总是可以执行题面中描述的操作。
可以证明结果字符串是唯一的。
输入:s = “leet**cod*e”
输出:“lecoe”
解释:从左到右执行移除操作:
- 距离第 1 个星号最近的字符是 “leet**code" 中的 ‘t’ ,s 变为 "leecod*e” 。
- 距离第 2 个星号最近的字符是 “leecode” 中的 ‘e’ ,s 变为 “lecod*e” 。
- 距离第 3 个星号最近的字符是 “lecod*e” 中的 ‘d’ ,s 变为 “lecoe” 。
不存在其他星号,返回 “lecoe” 。
示例 2:
输入:s = “erase*****”
输出:“”
解释:整个字符串都会被移除,所以返回空字符串。
这个题目其实会比第一题简单。只是一开始会不容易想到栈。最简单的思路就是遍历一遍字符串并一次进栈,在遇到星号时就将栈顶元素出栈,这样出栈的就是星号左边的元素。
class Solution {
public:
string removeStars(string s) {
string res;
for(auto c:s){
if(c!= '*'){
res += c;
}
else{
res.pop_back();
}
}
return res;
}
};