题目
2055.蜡烛之间的盘子
题目大意
给你一个长桌子,桌子上盘子和蜡烛排成一列。给你一个下标从 0 开始的字符串 s
,它只包含字符 '*'
和 '|'
,其中 '*'
表示一个 盘子 ,'|'
表示一支 蜡烛 。
同时给你一个下标从 0 开始的二维整数数组 queries
,其中 queries[i] = [lefti, righti]
表示 子字符串 s[lefti...righti]
(包含左右端点的字符)。对于每个查询,你需要找到 子字符串中 在 两支蜡烛之间 的盘子的 数目 。如果一个盘子在 子字符串中 左边和右边 都 至少有一支蜡烛,那么这个盘子满足在 两支蜡烛之间 。
- 比方说,
s = "||**||**|*"
,查询[3, 8]
,表示的是子字符串"*||***\**\***|"
。子字符串中在两支蜡烛之间的盘子数目为2
,子字符串中右边两个盘子在它们左边和右边 都 至少有一支蜡烛。
请你返回一个整数数组 answer
,其中 answer[i]
是第 i
个查询的答案。
样例
数据规模
思路
对于一个区间 [ L , R ] [L,R] [L,R],考虑有多少个盘子位于蜡烛之间。
可以抽象问题:认为蜡烛值 0 0 0,盘子值为 1 1 1,那么就是问区间 [ L , R ] [L,R] [L,R]之间最左端的 0 0 0和最右端的 0 0 0之间有多少个 1 1 1。
举例:对于数字1111010101111101111
,假设第一个
1
1
1的下标为
0
0
0,那么第一个
0
0
0的下标为
4
4
4,即最左边的
0
0
0(蜡烛)的下标为
4
4
4;最后一个
0
0
0的下标为
14
14
14,即最右边的
0
0
0(蜡烛)的下标为
14
14
14。原问题是求
[
0
,
18
]
[0,18]
[0,18]之间有多少个盘子位于蜡烛之间,现在问题变成了区间
[
4
,
14
]
[4,14]
[4,14]之间有多少个
1
1
1,那么该问题就抽象为了一维前缀和。
那么对于一个区间 [ L , R ] [L,R] [L,R]:如何找到 L L L右边的第一个蜡烛,又如何找到 R R R左边的第一个蜡烛?
- 定义一个数组
l
,该数组l[i]
用于求解i
左边的第一个蜡烛,如果左边没有蜡烛就设定为 − 1 -1 −1 - 定义一个数组
r
,该数组r[i]
用于求解i
右边的第一个蜡烛,如果右边没有蜡烛就设定为 − 1 -1 −1 - 定义一个数组
sum
,该数组sum[i]
用于求解区间 [ 0 , i ] [0,i] [0,i]之间 1 1 1的个数
对于每一个查询queries[i]
,首先取出区间
[
L
,
R
]
[L,R]
[L,R],找到
L
L
L右边的第一个蜡烛r[L]
,再找到
R
R
R左边的第一个蜡烛l[R]
,那么必须保证r[L]!=-1&&l[R]!=-1&&r[L]<l[R]
,在该条件下答案为sum[l[R]]-sum[r[L]-1]
否则答案就是
0
0
0,
代码
class Solution {
public:
vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
int n=s.length();
vector<int>sum(n),l(n),r(n);
for(int i=0,q=0,lmin=-1;i<n;i++){
if(s[i]=='*'){
q++;
}
if(s[i]=='|'){
lmin=i;
}
sum[i]=q;
l[i]=lmin;
}
for(int i=n-1,rmax=-1;i>=0;i--){
if(s[i]=='|'){
rmax=i;
}
r[i]=rmax;
}
vector<int>ans;
for(int i=0;i<queries.size();i++){
int L=queries[i][0],R=queries[i][1];
ans.push_back(((r[L]==-1||l[R]==-1||r[L]>=l[R])?0:sum[l[R]]-sum[r[L]]));
}
return ans;
}
};