题目来源:https://leetcode-cn.com/problems/plates-between-candles/
大致题意:
给一个字符串 s,由 | 和 * 组成,再给一个二维查询数组 queries,其中 queries[i][0] 为查询起始位置,queries[i][1] 为查询终点位置。
求出每次查询区间内,由两个 | 包围的 * 数目
思路
如果每次查询都遍历整个区间,一定会超时,而且有重复遍历
可以通过前缀和预处理来避免重复遍历
前缀和
使用前缀和存下截至每个位置的 * 数量,然后每次查询时找到区间左边界右侧第一个 | 的位置 start 和区间右边界左侧第一个 | 的位置 end,然后使用 end 位置前缀和减去 start 位置前缀和即为本次查询结果
具体实现时,可以使用两轮遍历分别求出当前位置左侧(右侧)第一个 | 的位置
public int[] platesBetweenCandles(String s, int[][] queries) {
int n = s.length();
int[] preSum = new int[n]; // 前缀和
int sum = 0;
int[] left = new int[n]; // 当前位置左侧第一个 | 的位置
int[] right = new int[n]; // 当前位置右侧第一个 | 的位置
int l = -1;
int r = -1;
// 正向遍历,求出前缀和以及左侧 | 的位置
for (int i = 0; i < n; i++) {
if (s.charAt(i) == '|') {
l = i;
} else {
sum++;
}
preSum[i] = sum;
left[i] = l;
}
// 反向遍历,求出右侧 | 的位置
for (int i = n - 1; i >= 0 ; i--) {
if (s.charAt(i) == '|') {
r = i;
}
right[i] = r;
}
int count = queries.length;
int[] ans = new int[count];
// 给出查询结果
for (int i = 0; i < count; i++) {
int start = right[queries[i][0]];
int end = left[queries[i][1]];
// start 或者 end 为 -1 表示区间内没有两个 |
if (start == -1 || end == -1 || start >= end) {
ans[i] = 0;
} else {
ans[i] = preSum[end] - preSum[start];
}
}
return ans;
}