Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 6e71522

Browse files
feat: add solutions to lc problem: No.2955 (#2070)
No.2955.Number of Same-End Substrings
1 parent d6e1fb1 commit 6e71522

File tree

8 files changed

+429
-6
lines changed

8 files changed

+429
-6
lines changed

‎solution/2900-2999/2955.Number of Same-End Substrings/README.md‎

Lines changed: 148 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,34 +51,179 @@
5151

5252
<!-- 这里可写通用的实现逻辑 -->
5353

54+
**方法一:前缀和 + 枚举**
55+
56+
我们可以预处理出每个字母的前缀和,记录在数组 $cnt$ 中,其中 $cnt[i][j]$ 表示第 $i$ 个字母在前 $j$ 个字符中出现的次数。这样,对于每个区间 $[l, r],ドル我们可以枚举区间中的每个字母 $c,ドル利用前缀和数组快速计算出 $c$ 在区间中出现的次数 $x,ドル我们任取其中两个,即可组成一个同尾子串,子串数为 $C_x^2=\frac{x(x-1)}{2},ドル加上区间中每个字母可以单独组成同尾子串的情况,一共有 $r - l + 1$ 个字母。因此,对于每个查询 $[l, r],ドル满足条件的同尾子串数为 $r - l + 1 + \sum_{c \in \Sigma} \frac{x_c(x_c-1)}{2},ドル其中 $x_c$ 表示字母 $c$ 在区间 $[l, r]$ 中出现的次数。
57+
58+
时间复杂度 $O((n + m) \times |\Sigma|),ドル空间复杂度 $O(n \times |\Sigma|)$。其中 $n$ 和 $m$ 分别为字符串 $s$ 的长度和查询数,而 $\Sigma$ 表示字符串 $s$ 中出现的字母集合,本题中 $|\Sigma|=26$。
59+
5460
<!-- tabs:start -->
5561

5662
### **Python3**
5763

5864
<!-- 这里可写当前语言的特殊实现逻辑 -->
5965

6066
```python
61-
67+
class Solution:
68+
def sameEndSubstringCount(self, s: str, queries: List[List[int]]) -> List[int]:
69+
n = len(s)
70+
cs = set(s)
71+
cnt = {c: [0] * (n + 1) for c in cs}
72+
for i, a in enumerate(s, 1):
73+
for c in cs:
74+
cnt[c][i] = cnt[c][i - 1]
75+
cnt[a][i] += 1
76+
ans = []
77+
for l, r in queries:
78+
t = r - l + 1
79+
for c in cs:
80+
x = cnt[c][r + 1] - cnt[c][l]
81+
t += x * (x - 1) // 2
82+
ans.append(t)
83+
return ans
6284
```
6385

6486
### **Java**
6587

6688
<!-- 这里可写当前语言的特殊实现逻辑 -->
6789

6890
```java
69-
91+
class Solution {
92+
public int[] sameEndSubstringCount(String s, int[][] queries) {
93+
int n = s.length();
94+
int[][] cnt = new int[26][n + 1];
95+
for (int j = 1; j <= n; ++j) {
96+
for (int i = 0; i < 26; ++i) {
97+
cnt[i][j] = cnt[i][j - 1];
98+
}
99+
cnt[s.charAt(j - 1) - 'a'][j]++;
100+
}
101+
int m = queries.length;
102+
int[] ans = new int[m];
103+
for (int k = 0; k < m; ++k) {
104+
int l = queries[k][0], r = queries[k][1];
105+
ans[k] = r - l + 1;
106+
for (int i = 0; i < 26; ++i) {
107+
int x = cnt[i][r + 1] - cnt[i][l];
108+
ans[k] += x * (x - 1) / 2;
109+
}
110+
}
111+
return ans;
112+
}
113+
}
70114
```
71115

72116
### **C++**
73117

74118
```cpp
75-
119+
class Solution {
120+
public:
121+
vector<int> sameEndSubstringCount(string s, vector<vector<int>>& queries) {
122+
int n = s.size();
123+
int cnt[26][n + 1];
124+
memset(cnt, 0, sizeof(cnt));
125+
for (int j = 1; j <= n; ++j) {
126+
for (int i = 0; i < 26; ++i) {
127+
cnt[i][j] = cnt[i][j - 1];
128+
}
129+
cnt[s[j - 1] - 'a'][j]++;
130+
}
131+
vector<int> ans;
132+
for (auto& q : queries) {
133+
int l = q[0], r = q[1];
134+
ans.push_back(r - l + 1);
135+
for (int i = 0; i < 26; ++i) {
136+
int x = cnt[i][r + 1] - cnt[i][l];
137+
ans.back() += x * (x - 1) / 2;
138+
}
139+
}
140+
return ans;
141+
}
142+
};
76143
```
77144
78145
### **Go**
79146
80147
```go
148+
func sameEndSubstringCount(s string, queries [][]int) []int {
149+
n := len(s)
150+
cnt := make([][]int, 26)
151+
for i := 0; i < 26; i++ {
152+
cnt[i] = make([]int, n+1)
153+
}
154+
155+
for j := 1; j <= n; j++ {
156+
for i := 0; i < 26; i++ {
157+
cnt[i][j] = cnt[i][j-1]
158+
}
159+
cnt[s[j-1]-'a'][j]++
160+
}
161+
162+
var ans []int
163+
for _, q := range queries {
164+
l, r := q[0], q[1]
165+
ans = append(ans, r-l+1)
166+
for i := 0; i < 26; i++ {
167+
x := cnt[i][r+1] - cnt[i][l]
168+
ans[len(ans)-1] += x * (x - 1) / 2
169+
}
170+
}
171+
172+
return ans
173+
}
174+
```
175+
176+
### **TypeScript**
177+
178+
```ts
179+
function sameEndSubstringCount(s: string, queries: number[][]): number[] {
180+
const n: number = s.length;
181+
const cnt: number[][] = Array.from({ length: 26 }, () => Array(n + 1).fill(0));
182+
for (let j = 1; j <= n; j++) {
183+
for (let i = 0; i < 26; i++) {
184+
cnt[i][j] = cnt[i][j - 1];
185+
}
186+
cnt[s.charCodeAt(j - 1) - 'a'.charCodeAt(0)][j]++;
187+
}
188+
const ans: number[] = [];
189+
for (const [l, r] of queries) {
190+
ans.push(r - l + 1);
191+
for (let i = 0; i < 26; i++) {
192+
const x: number = cnt[i][r + 1] - cnt[i][l];
193+
ans[ans.length - 1] += (x * (x - 1)) / 2;
194+
}
195+
}
196+
return ans;
197+
}
198+
```
81199

200+
### **Rust**
201+
202+
```rust
203+
impl Solution {
204+
pub fn same_end_substring_count(s: String, queries: Vec<Vec<i32>>) -> Vec<i32> {
205+
let n = s.len();
206+
let mut cnt: Vec<Vec<i32>> = vec![vec![0; n + 1]; 26];
207+
for j in 1..=n {
208+
for i in 0..26 {
209+
cnt[i][j] = cnt[i][j - 1];
210+
}
211+
cnt[(s.as_bytes()[j - 1] as usize) - (b'a' as usize)][j] += 1;
212+
}
213+
let mut ans: Vec<i32> = Vec::new();
214+
for q in queries.iter() {
215+
let l = q[0] as usize;
216+
let r = q[1] as usize;
217+
let mut t = (r - l + 1) as i32;
218+
for i in 0..26 {
219+
let x = cnt[i][r + 1] - cnt[i][l];
220+
t += (x * (x - 1)) / 2;
221+
}
222+
ans.push(t);
223+
}
224+
ans
225+
}
226+
}
82227
```
83228

84229
### **...**

‎solution/2900-2999/2955.Number of Same-End Substrings/README_EN.md‎

Lines changed: 148 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,30 +47,175 @@
4747

4848
## Solutions
4949

50+
**Solution 1: Prefix Sum + Enumeration**
51+
52+
We can preprocess the prefix sum for each letter and record it in the array $cnt,ドル where $cnt[i][j]$ represents the number of times the $i$-th letter appears in the first $j$ characters. In this way, for each interval $[l, r],ドル we can enumerate each letter $c$ in the interval, quickly calculate the number of times $c$ appears in the interval $x$ using the prefix sum array. We can arbitrarily choose two of them to form a tail-equal substring, the number of substrings is $C_x^2=\frac{x(x-1)}{2},ドル plus the situation where each letter in the interval can form a tail-equal substring alone, there are $r - l + 1$ letters in total. Therefore, for each query $[l, r],ドル the number of tail-equal substrings that meet the conditions is $r - l + 1 + \sum_{c \in \Sigma} \frac{x_c(x_c-1)}{2},ドル where $x_c$ represents the number of times the letter $c$ appears in the interval $[l, r]$.
53+
54+
The time complexity is $O((n + m) \times |\Sigma|),ドル and the space complexity is $O(n \times |\Sigma|)$. Here, $n$ and $m$ are the lengths of the string $s$ and the number of queries, respectively, and $\Sigma$ represents the set of letters appearing in the string $s,ドル in this problem $|\Sigma|=26$.
55+
5056
<!-- tabs:start -->
5157

5258
### **Python3**
5359

5460
```python
55-
61+
class Solution:
62+
def sameEndSubstringCount(self, s: str, queries: List[List[int]]) -> List[int]:
63+
n = len(s)
64+
cs = set(s)
65+
cnt = {c: [0] * (n + 1) for c in cs}
66+
for i, a in enumerate(s, 1):
67+
for c in cs:
68+
cnt[c][i] = cnt[c][i - 1]
69+
cnt[a][i] += 1
70+
ans = []
71+
for l, r in queries:
72+
t = r - l + 1
73+
for c in cs:
74+
x = cnt[c][r + 1] - cnt[c][l]
75+
t += x * (x - 1) // 2
76+
ans.append(t)
77+
return ans
5678
```
5779

5880
### **Java**
5981

6082
```java
61-
83+
class Solution {
84+
public int[] sameEndSubstringCount(String s, int[][] queries) {
85+
int n = s.length();
86+
int[][] cnt = new int[26][n + 1];
87+
for (int j = 1; j <= n; ++j) {
88+
for (int i = 0; i < 26; ++i) {
89+
cnt[i][j] = cnt[i][j - 1];
90+
}
91+
cnt[s.charAt(j - 1) - 'a'][j]++;
92+
}
93+
int m = queries.length;
94+
int[] ans = new int[m];
95+
for (int k = 0; k < m; ++k) {
96+
int l = queries[k][0], r = queries[k][1];
97+
ans[k] = r - l + 1;
98+
for (int i = 0; i < 26; ++i) {
99+
int x = cnt[i][r + 1] - cnt[i][l];
100+
ans[k] += x * (x - 1) / 2;
101+
}
102+
}
103+
return ans;
104+
}
105+
}
62106
```
63107

64108
### **C++**
65109

66110
```cpp
67-
111+
class Solution {
112+
public:
113+
vector<int> sameEndSubstringCount(string s, vector<vector<int>>& queries) {
114+
int n = s.size();
115+
int cnt[26][n + 1];
116+
memset(cnt, 0, sizeof(cnt));
117+
for (int j = 1; j <= n; ++j) {
118+
for (int i = 0; i < 26; ++i) {
119+
cnt[i][j] = cnt[i][j - 1];
120+
}
121+
cnt[s[j - 1] - 'a'][j]++;
122+
}
123+
vector<int> ans;
124+
for (auto& q : queries) {
125+
int l = q[0], r = q[1];
126+
ans.push_back(r - l + 1);
127+
for (int i = 0; i < 26; ++i) {
128+
int x = cnt[i][r + 1] - cnt[i][l];
129+
ans.back() += x * (x - 1) / 2;
130+
}
131+
}
132+
return ans;
133+
}
134+
};
68135
```
69136
70137
### **Go**
71138
72139
```go
140+
func sameEndSubstringCount(s string, queries [][]int) []int {
141+
n := len(s)
142+
cnt := make([][]int, 26)
143+
for i := 0; i < 26; i++ {
144+
cnt[i] = make([]int, n+1)
145+
}
146+
147+
for j := 1; j <= n; j++ {
148+
for i := 0; i < 26; i++ {
149+
cnt[i][j] = cnt[i][j-1]
150+
}
151+
cnt[s[j-1]-'a'][j]++
152+
}
153+
154+
var ans []int
155+
for _, q := range queries {
156+
l, r := q[0], q[1]
157+
ans = append(ans, r-l+1)
158+
for i := 0; i < 26; i++ {
159+
x := cnt[i][r+1] - cnt[i][l]
160+
ans[len(ans)-1] += x * (x - 1) / 2
161+
}
162+
}
163+
164+
return ans
165+
}
166+
```
167+
168+
### **TypeScript**
169+
170+
```ts
171+
function sameEndSubstringCount(s: string, queries: number[][]): number[] {
172+
const n: number = s.length;
173+
const cnt: number[][] = Array.from({ length: 26 }, () => Array(n + 1).fill(0));
174+
for (let j = 1; j <= n; j++) {
175+
for (let i = 0; i < 26; i++) {
176+
cnt[i][j] = cnt[i][j - 1];
177+
}
178+
cnt[s.charCodeAt(j - 1) - 'a'.charCodeAt(0)][j]++;
179+
}
180+
const ans: number[] = [];
181+
for (const [l, r] of queries) {
182+
ans.push(r - l + 1);
183+
for (let i = 0; i < 26; i++) {
184+
const x: number = cnt[i][r + 1] - cnt[i][l];
185+
ans[ans.length - 1] += (x * (x - 1)) / 2;
186+
}
187+
}
188+
return ans;
189+
}
190+
```
73191

192+
### **Rust**
193+
194+
```rust
195+
impl Solution {
196+
pub fn same_end_substring_count(s: String, queries: Vec<Vec<i32>>) -> Vec<i32> {
197+
let n = s.len();
198+
let mut cnt: Vec<Vec<i32>> = vec![vec![0; n + 1]; 26];
199+
for j in 1..=n {
200+
for i in 0..26 {
201+
cnt[i][j] = cnt[i][j - 1];
202+
}
203+
cnt[(s.as_bytes()[j - 1] as usize) - (b'a' as usize)][j] += 1;
204+
}
205+
let mut ans: Vec<i32> = Vec::new();
206+
for q in queries.iter() {
207+
let l = q[0] as usize;
208+
let r = q[1] as usize;
209+
let mut t = (r - l + 1) as i32;
210+
for i in 0..26 {
211+
let x = cnt[i][r + 1] - cnt[i][l];
212+
t += (x * (x - 1)) / 2;
213+
}
214+
ans.push(t);
215+
}
216+
ans
217+
}
218+
}
74219
```
75220

76221
### **...**
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
class Solution {
2+
public:
3+
vector<int> sameEndSubstringCount(string s, vector<vector<int>>& queries) {
4+
int n = s.size();
5+
int cnt[26][n + 1];
6+
memset(cnt, 0, sizeof(cnt));
7+
for (int j = 1; j <= n; ++j) {
8+
for (int i = 0; i < 26; ++i) {
9+
cnt[i][j] = cnt[i][j - 1];
10+
}
11+
cnt[s[j - 1] - 'a'][j]++;
12+
}
13+
vector<int> ans;
14+
for (auto& q : queries) {
15+
int l = q[0], r = q[1];
16+
ans.push_back(r - l + 1);
17+
for (int i = 0; i < 26; ++i) {
18+
int x = cnt[i][r + 1] - cnt[i][l];
19+
ans.back() += x * (x - 1) / 2;
20+
}
21+
}
22+
return ans;
23+
}
24+
};

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /