Skip to content

Commit ec6cc34

Browse files
authored
feat: add solutions to lcci problem: No.16.18 (doocs#1653)
No.16.18.Pattern Matching
1 parent cfcc7e0 commit ec6cc34

File tree

8 files changed

+731
-1
lines changed

8 files changed

+731
-1
lines changed

lcci/16.18.Pattern Matching/README.md

+257
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
## 题目描述
66

77
<!-- 这里写题目描述 -->
8+
89
<p>你有两个字符串,即<code>pattern</code>和<code>value</code>。 <code>pattern</code>字符串由字母<code>"a"</code>和<code>"b"</code>组成,用于描述字符串中的模式。例如,字符串<code>"catcatgocatgo"</code>匹配模式<code>"aabab"</code>(其中<code>"cat"</code>是<code>"a"</code>,<code>"go"</code>是<code>"b"</code>),该字符串也匹配像<code>"a"</code>、<code>"ab"</code>和<code>"b"</code>这样的模式。但需注意<code>"a"</code>和<code>"b"</code>不能同时表示相同的字符串。编写一个方法判断<code>value</code>字符串是否匹配<code>pattern</code>字符串。</p>
910
<p><strong>示例 1:</strong></p>
1011
<pre><strong>输入:</strong> pattern = "abba", value = "dogcatcatdog"
@@ -33,22 +34,278 @@
3334
## 解法
3435

3536
<!-- 这里可写通用的实现逻辑 -->
37+
38+
**方法一:枚举**
39+
40+
我们先统计出模式串 $pattern$ 中 `'a'``'b'` 的个数,分别为 $cnt[0]$ 和 $cnt[1]$。记字符串 $value$ 的长度为 $n$。
41+
42+
如果 $cnt[0]=0$,说明模式串中只包含字符 `'b'`,那么我们需要判断 $n$ 是否是 $cnt[1]$ 的倍数,以及 $value$ 是否可以分割成 $cnt[1]$ 个长度为 $n/cnt[1]$ 的子串,且这些子串都相同。如果不满足,直接返回 $false$ 即可。
43+
44+
如果 $cnt[1]=0$,说明模式串中只包含字符 `'a'`,那么我们需要判断 $n$ 是否是 $cnt[0]$ 的倍数,以及 $value$ 是否可以分割成 $cnt[0]$ 个长度为 $n/cnt[0]$ 的子串,且这些子串都相同。如果不满足,直接返回 $false$ 即可。
45+
46+
接下来,我们记字符 `'a'` 所匹配的字符串的长度 $la$,字符 `'b'` 所匹配的字符串的长度 $lb$。那么有 $la \times cnt[0] + lb \times cnt[1] = n$。如果我们枚举 $la$,就可以知道 $lb$ 的值了。因此我们可以枚举 $la$,只需要判断是否存在一个整数 $lb$,满足上述等式即可。
47+
48+
时间复杂度 $O(n^2)$,空间复杂度 $O(n)$。其中 $n$ 为字符串 $value$ 的长度。
49+
3650
<!-- tabs:start -->
3751

3852
### **Python3**
3953

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

4256
```python
57+
class Solution:
58+
def patternMatching(self, pattern: str, value: str) -> bool:
59+
def check(la: int, lb: int) -> bool:
60+
i = 0
61+
a, b = "", ""
62+
for c in pattern:
63+
if c == "a":
64+
if a and value[i : i + la] != a:
65+
return False
66+
a = value[i : i + la]
67+
i += la
68+
else:
69+
if b and value[i : i + lb] != b:
70+
return False
71+
b = value[i : i + lb]
72+
i += lb
73+
return a != b
4374

75+
n = len(value)
76+
cnt = Counter(pattern)
77+
if cnt["a"] == 0:
78+
return n % cnt["b"] == 0 and value[: n // cnt["b"]] * cnt["b"] == value
79+
if cnt["b"] == 0:
80+
return n % cnt["a"] == 0 and value[: n // cnt["a"]] * cnt["a"] == value
81+
82+
for la in range(n + 1):
83+
if la * cnt["a"] > n:
84+
break
85+
lb, mod = divmod(n - la * cnt["a"], cnt["b"])
86+
if mod == 0 and check(la, lb):
87+
return True
88+
return False
4489
```
4590

4691
### **Java**
4792

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

5095
```java
96+
class Solution {
97+
private String pattern;
98+
private String value;
99+
100+
public boolean patternMatching(String pattern, String value) {
101+
this.pattern = pattern;
102+
this.value = value;
103+
int[] cnt = new int[2];
104+
for (char c : pattern.toCharArray()) {
105+
++cnt[c - 'a'];
106+
}
107+
int n = value.length();
108+
if (cnt[0] == 0) {
109+
return n % cnt[1] == 0 && value.substring(0, n / cnt[1]).repeat(cnt[1]).equals(value);
110+
}
111+
if (cnt[1] == 0) {
112+
return n % cnt[0] == 0 && value.substring(0, n / cnt[0]).repeat(cnt[0]).equals(value);
113+
}
114+
for (int la = 0; la <= n; ++la) {
115+
if (la * cnt[0] > n) {
116+
break;
117+
}
118+
if ((n - la * cnt[0]) % cnt[1] == 0) {
119+
int lb = (n - la * cnt[0]) / cnt[1];
120+
if (check(la, lb)) {
121+
return true;
122+
}
123+
}
124+
}
125+
return false;
126+
}
127+
128+
private boolean check(int la, int lb) {
129+
int i = 0;
130+
String a = null, b = null;
131+
for (char c : pattern.toCharArray()) {
132+
if (c == 'a') {
133+
if (a != null && !a.equals(value.substring(i, i + la))) {
134+
return false;
135+
}
136+
a = value.substring(i, i + la);
137+
i += la;
138+
} else {
139+
if (b != null && !b.equals(value.substring(i, i + lb))) {
140+
return false;
141+
}
142+
b = value.substring(i, i + lb);
143+
i += lb;
144+
}
145+
}
146+
return !a.equals(b);
147+
}
148+
}
149+
```
150+
151+
### **C++**
152+
153+
```cpp
154+
class Solution {
155+
public:
156+
bool patternMatching(string pattern, string value) {
157+
int n = value.size();
158+
int cnt[2]{};
159+
for (char c : pattern) {
160+
cnt[c - 'a']++;
161+
}
162+
if (cnt[0] == 0) {
163+
return n % cnt[1] == 0 && repeat(value.substr(0, n / cnt[1]), cnt[1]) == value;
164+
}
165+
if (cnt[1] == 0) {
166+
return n % cnt[0] == 0 && repeat(value.substr(0, n / cnt[0]), cnt[0]) == value;
167+
}
168+
auto check = [&](int la, int lb) {
169+
int i = 0;
170+
string a, b;
171+
for (char c : pattern) {
172+
if (c == 'a') {
173+
if (!a.empty() && a != value.substr(i, la)) {
174+
return false;
175+
}
176+
a = value.substr(i, la);
177+
i += la;
178+
} else {
179+
if (!b.empty() && b != value.substr(i, lb)) {
180+
return false;
181+
}
182+
b = value.substr(i, lb);
183+
i += lb;
184+
}
185+
}
186+
return a != b;
187+
};
188+
for (int la = 0; la <= n; ++la) {
189+
if (la * cnt[0] > n) {
190+
break;
191+
}
192+
if ((n - la * cnt[0]) % cnt[1] == 0) {
193+
int lb = (n - la * cnt[0]) / cnt[1];
194+
if (check(la, lb)) {
195+
return true;
196+
}
197+
}
198+
}
199+
return false;
200+
}
201+
202+
string repeat(string s, int n) {
203+
string ans;
204+
while (n--) {
205+
ans += s;
206+
}
207+
return ans;
208+
}
209+
};
210+
```
211+
212+
### **Go**
213+
214+
```go
215+
func patternMatching(pattern string, value string) bool {
216+
cnt := [2]int{}
217+
for _, c := range pattern {
218+
cnt[c-'a']++
219+
}
220+
n := len(value)
221+
if cnt[0] == 0 {
222+
return n%cnt[1] == 0 && strings.Repeat(value[:n/cnt[1]], cnt[1]) == value
223+
}
224+
if cnt[1] == 0 {
225+
return n%cnt[0] == 0 && strings.Repeat(value[:n/cnt[0]], cnt[0]) == value
226+
}
227+
check := func(la, lb int) bool {
228+
i := 0
229+
a, b := "", ""
230+
for _, c := range pattern {
231+
if c == 'a' {
232+
if a != "" && value[i:i+la] != a {
233+
return false
234+
}
235+
a = value[i : i+la]
236+
i += la
237+
} else {
238+
if b != "" && value[i:i+lb] != b {
239+
return false
240+
}
241+
b = value[i : i+lb]
242+
i += lb
243+
}
244+
}
245+
return a != b
246+
}
247+
for la := 0; la <= n; la++ {
248+
if la*cnt[0] > n {
249+
break
250+
}
251+
if (n-la*cnt[0])%cnt[1] == 0 {
252+
lb := (n - la*cnt[0]) / cnt[1]
253+
if check(la, lb) {
254+
return true
255+
}
256+
}
257+
}
258+
return false
259+
}
260+
```
261+
262+
### **TypeScript**
51263

264+
```ts
265+
function patternMatching(pattern: string, value: string): boolean {
266+
const cnt: number[] = [0, 0];
267+
for (const c of pattern) {
268+
cnt[c === 'a' ? 0 : 1]++;
269+
}
270+
const n = value.length;
271+
if (cnt[0] === 0) {
272+
return n % cnt[1] === 0 && value.slice(0, (n / cnt[1]) | 0).repeat(cnt[1]) === value;
273+
}
274+
if (cnt[1] === 0) {
275+
return n % cnt[0] === 0 && value.slice(0, (n / cnt[0]) | 0).repeat(cnt[0]) === value;
276+
}
277+
const check = (la: number, lb: number) => {
278+
let i = 0;
279+
let a = '';
280+
let b = '';
281+
for (const c of pattern) {
282+
if (c === 'a') {
283+
if (a && a !== value.slice(i, i + la)) {
284+
return false;
285+
}
286+
a = value.slice(i, (i += la));
287+
} else {
288+
if (b && b !== value.slice(i, i + lb)) {
289+
return false;
290+
}
291+
b = value.slice(i, (i += lb));
292+
}
293+
}
294+
return a !== b;
295+
};
296+
for (let la = 0; la <= n; ++la) {
297+
if (la * cnt[0] > n) {
298+
break;
299+
}
300+
if ((n - la * cnt[0]) % cnt[1] === 0) {
301+
const lb = ((n - la * cnt[0]) / cnt[1]) | 0;
302+
if (check(la, lb)) {
303+
return true;
304+
}
305+
}
306+
}
307+
return false;
308+
}
52309
```
53310

54311
### **...**

0 commit comments

Comments
 (0)