给你一个长桌子,桌子上盘子和蜡烛排成一列。给你一个下标从 0 开始的字符串 s ,它只包含字符 ‘’ 和 ‘|’ ,其中 '’ 表示一个 盘子 ,‘|’ 表示一支 蜡烛 。
同时给你一个下标从 0 开始的二维整数数组 queries ,其中 queries[i] = [lefti, righti] 表示 子字符串 s[lefti…righti] (包含左右端点的字符)。对于每个查询,你需要找到 子字符串中 在 两支蜡烛之间 的盘子的 数目 。如果一个盘子在 子字符串中 左边和右边 都 至少有一支蜡烛,那么这个盘子满足在 两支蜡烛之间 。
比方说,s = “|||||" ,查询 [3, 8] ,表示的是子字符串 "||**|” 。子字符串中在两支蜡烛之间的盘子数目为 2 ,子字符串中右边两个盘子在它们左边和右边 都 至少有一支蜡烛。
请你返回一个整数数组 answer ,其中 answer[i] 是第 i 个查询的答案。
示例1
示例2
第一次尝试(12/36)
class Solution {
public:
vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
vector<int> answer;
for(const auto& query : queries){
int count = 0;
bool flag = false;
int start = query[0];
int end = query[1];
while(s[start] != '|'){
start++;
}
while(s[end] != '|'){
end--;
}
for(int i = start;i <= end;i++){
if(s[i] == '|') {
continue;
}
count++;
}
answer.push_back(count);
}
return answer;
}
};
一开始想的代码,找到两个边界,然后遍历里面的元素,算出answer,在12/36示例的时候超时。发现计算每个queries里面的区间的时候,都要重复遍历一遍元素,考虑可以采用预处理。
第一次优化代码(22/36)
class Solution {
public:
vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
vector<int> memo(s.size(), 0);
int total = 0;
for(int i = 0;i < s.size();i++){
if(s[i] == '*') {
total++;
}
memo[i] = total;
}
vector<int> answer;
for(const auto& query : queries){
int first = query[0];
int second = query[1];
while(s[first] != '|' && first < second){
first++;
}
while(s[second] != '|' && second > first){
second--;
}
if(first != second){
int count = memo[second] - memo[first];
answer.push_back(count);
}else{
answer.push_back((int) 0);
}
}
return answer;
}
};
定义了一个memo数组,在进行对queries的遍历前,先计算出字符串在 i 之前的累积蜡烛数量。进行测试,在22/36示例的时候超时。
发现在测试的时候在两根’|‘中间输入了很多很多’ * ',观察代码发现,在每次计算新的query的最外边两根蜡烛位置的时候,如果一直找不到蜡烛,就会几乎遍历完整个区间,这会消耗很多内存。
第二次优化代码(通过)
class Solution {
public:
vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
vector<int> memo(s.size(), 0);
vector<int> leftCandle(s.size(), -1);
vector<int> rightCandle(s.size(), -1);
int total = 0;
int lastCandle = -1;
for(int i = 0;i < s.size();i++){
if(s[i] == '*') {
total++;
}else{
lastCandle = i;
}
memo[i] = total;
leftCandle[i] = lastCandle;
}
lastCandle = -1;
for(int i = s.size()-1;i >= 0;i--){
if(s[i] == '|'){
lastCandle = i;
}
rightCandle[i] = lastCandle;
}
vector<int> answer;
for(const auto& query : queries){
int second = leftCandle[query[1]];
int first = rightCandle[query[0]];
if(first != -1 && second != -1 && first < second){
answer.push_back(memo[second] - memo[first]);
}else{
answer.push_back(0);
}
}
return answer;
}
};
定义了两个数组
vector<int> leftCandle(s.size(), -1); //储存左边最近的蜡烛
vector<int> rightCandle(s.size(), -1); //储存右边最近的蜡烛
这样,就不需要在循环中再次嵌套循环来找到最外边的两根蜡烛的位置。
if(first != -1 && second != -1 && first < second){
answer.push_back(memo[second] - memo[first]);
}else{
answer.push_back(0);
}
只要两边都有蜡烛,且first < second
两根蜡烛顺序正确,就会返回memo[second] - memo[first]
,否则返回0。