题目
力扣
思路一 二分+前缀和
记录每个蜡烛的位置之前满足条件的*的个数,再对于每一个查询,通过二分,找到左边界右边最近的蜡烛,右边界左边最近的蜡烛,将其中的盘子数量相减。
代码一
class Solution {
public:
vector<int> idx, sum;
vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
vector<int> ans;
bool flag = false; //前面是否有蜡烛
int cnt = 0;
for(int i = 0; i < s.size(); i++){
if(s[i] == '|'){
idx.push_back(i);
if(!flag){
flag = true;
sum.push_back(0);
}else{
sum.push_back(cnt);
}
}else{
if(flag) cnt++;
}
}
for(auto query : queries){
int left = binarySearch(query[0],true), right = binarySearch(query[1],false);
// cout<<left<<' '<<right<<endl;
if(right > left)
ans.push_back(sum[right] - sum[left]);
else
ans.push_back(0);
}
return ans;
}
int binarySearch(int x, bool flag){
int l = 0, r = idx.size() - 1;
while(l < r){
int mid = l + r >> 1;
if(flag){
//找到第一个满足idx[i]>=x的i
if(idx[mid] >= x) r = mid;
else l = mid + 1;
}else{
//找到最后一个满足idx[i]<=x的i
if(idx[mid + 1] > x) r = mid;
else l = mid + 1;
}
}
return l;
}
};
思路二 前缀和
在处理前缀和时,记录每个位置左右最近的蜡烛,避免每次二分。
代码二
class Solution {
public:
vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
int n = s.size(), m = queries.size();
vector<int> l(n), r(n), ans(m), sum(n + 1);
for(int i = 0, j = n - 1, p = -1, q = -1; i < n; i++, j--){
if(s[i] == '|') p = i;
if(s[j] == '|') q = j;
l[i] = p;
r[j] = q;
sum[i + 1] = sum[i] + (s[i] == '*');
}
for(int i = 0; i < m; i++){
int a = queries[i][0], b = queries[i][1];
int c = r[a], d = l[b];
if(c < d && c != -1) ans[i] = sum[d + 1] - sum[c + 1];
}
return ans;
}
};