You are given a 0-indexed string s, and a 2D array of integers
queries, where queries[i] = [li, ri] indicates a substring of s starting from the index li and ending at the index ri (both inclusive), i.e.
s[li..ri].
Return an arrayanswhereans[i]is the number ofsame-end substrings ofqueries[i].
A 0-indexed string t of length n is called same-end if it has the same character at both of its ends, i.e., t[0] == t[n - 1].
A substring is a contiguous non-empty sequence of characters within a string.
Input: s ="abcaab", queries =[[0,0],[1,4],[2,5],[0,5]]Output: [1,5,5,10]Explanation: Here is the same-end substrings of each query:1st query: s[0..0]is"a" which has 1 same-end substring:"**_a_** ".2nd query: s[1..4]is"bcaa" which has 5 same-end substrings:"**_b_** caa","b** _c_** aa","bc** _a_** a","bca** _a_** ","bc** _aa_** ".3rd query: s[2..5]is"caab" which has 5 same-end substrings:"**_c_** aab","c** _a_** ab","ca** _a_** b","caa** _b_** ","c** _aa_** b".4th query: s[0..5]is"abcaab" which has 10 same-end substrings:"**_a_** bcaab","a** _b_** caab","ab** _c_** aab","abc** _a_** ab","abca** _a_** b","abcaa** _b_** ","abc** _aa_** b","**_abca_** ab","**_abcaa_** b","a** _bcaab_** ".
Example 2:
1
2
3
Input: s ="abcd", queries =[[0,3]]Output: [4]Explanation: The only query is s[0..3] which is"abcd". It has 4 same-end substrings:"**_a_** bcd","a** _b_** cd","ab** _c_** d","abc** _d_** ".
For a substring, the number of same-end substrings is the sum over all characters of the number of ways to pick two positions (or one) with that character at both ends. We can precompute prefix sums for each character to answer each query efficiently.
#include<vector>#include<string>usingnamespace std;
classSolution {
public: vector<int> sameEndSubstrings(string s, vector<vector<int>>& queries) {
int n = s.size();
vector<vector<int>> pre(26, vector<int>(n+1, 0));
for (int i =0; i < n; ++i) {
for (int c =0; c <26; ++c) pre[c][i+1] = pre[c][i];
pre[s[i]-'a'][i+1]++;
}
vector<int> ans;
for (auto& q : queries) {
int l = q[0], r = q[1], res =0;
for (int c =0; c <26; ++c) {
int cnt = pre[c][r+1] - pre[c][l];
res += cnt + cnt*(cnt-1)/2;
}
ans.push_back(res);
}
return ans;
}
};
classSolution {
publicint[]sameEndSubstrings(String s, int[][] queries) {
int n = s.length();
int[][] pre =newint[26][n+1];
for (int i = 0; i < n; ++i) {
for (int c = 0; c < 26; ++c) pre[c][i+1]= pre[c][i];
pre[s.charAt(i)-'a'][i+1]++;
}
int[] ans =newint[queries.length];
for (int qi = 0; qi < queries.length; ++qi) {
int l = queries[qi][0], r = queries[qi][1], res = 0;
for (int c = 0; c < 26; ++c) {
int cnt = pre[c][r+1]- pre[c][l];
res += cnt + cnt*(cnt-1)/2;
}
ans[qi]= res;
}
return ans;
}
}
classSolution {
funsameEndSubstrings(s: String, queries: Array<IntArray>): IntArray {
val n = s.length
val pre = Array(26) { IntArray(n+1) }
for (i in0 until n) {
for (c in0 until 26) pre[c][i+1] = pre[c][i]
pre[s[i]-'a'][i+1]++ }
val ans = IntArray(queries.size)
for ((qi, q) in queries.withIndex()) {
val(l, r) = q
var res = 0for (c in0 until 26) {
val cnt = pre[c][r+1] - pre[c][l]
res += cnt + cnt*(cnt-1)/2 }
ans[qi] = res
}
return ans
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
classSolution:
defsameEndSubstrings(self, s: str, queries: list[list[int]]) -> list[int]:
n = len(s)
pre = [[0]*(n+1) for _ in range(26)]
for i, ch in enumerate(s):
for c in range(26):
pre[c][i+1] = pre[c][i]
pre[ord(ch)-97][i+1] +=1 ans = []
for l, r in queries:
res =0for c in range(26):
cnt = pre[c][r+1] - pre[c][l]
res += cnt + cnt*(cnt-1)//2 ans.append(res)
return ans
impl Solution {
pubfnsame_end_substrings(s: String, queries: Vec<Vec<i32>>) -> Vec<i32> {
let n = s.len();
let s = s.as_bytes();
letmut pre =vec![vec![0; n+1]; 26];
for i in0..n {
for c in0..26 { pre[c][i+1] = pre[c][i]; }
pre[(s[i]-b'a') asusize][i+1] +=1;
}
letmut ans =vec![];
for q in queries {
let l = q[0] asusize;
let r = q[1] asusize;
letmut res =0;
for c in0..26 {
let cnt = pre[c][r+1] - pre[c][l];
res += cnt + cnt*(cnt-1)/2;
}
ans.push(res asi32);
}
ans
}
}