16.18. Pattern Matching
September 12, 2026 · View on GitHub
Description
You are given two strings, pattern and value. The pattern string consists of just the letters a and b, describing a pattern within a string. For example, the string catcatgocatgo matches the pattern aabab (where cat is a and go is b). It also matches patterns like a, ab, and b. Write a method to determine if value matches pattern. a and b cannot be the same string.
Example 1:
Input: pattern = "abba", value = "dogcatcatdog"
Output: true
Example 2:
Input: pattern = "abba", value = "dogcatcatfish"
Output: false
Example 3:
Input: pattern = "aaaa", value = "dogcatcatdog"
Output: false
Example 4:
Input: pattern = "abba", value = "dogdogdogdog"
Output: true
Explanation: "a"="dogdog",b="",vice versa.
Note:
0 <= len(pattern) <= 10000 <= len(value) <= 1000patternonly contains"a"and"b",valueonly contains lowercase letters.
Solutions
Solution 1: Enumeration
Thinking
aandbeach stand for a (possibly empty) string. Searching the product of their contents is huge.Once the two lengths are fixed, the match is determined; it remains to check consistency and .
Handle a single-letter pattern first. Enumerate , deduce from the total length, and
checkslices along the pattern. Both the enum and each check are linear.
We first count the number of characters 'a' and 'b' in the pattern string , denoted as and , respectively. Let the length of the string be .
If , it means that the pattern string only contains the character 'b'. We need to check whether is a multiple of , and whether can be divided into substrings of length , and all these substrings are the same. If not, return directly.
If , it means that the pattern string only contains the character 'a'. We need to check whether is a multiple of , and whether can be divided into substrings of length , and all these substrings are the same. If not, return directly.
Next, we denote the length of the string matched by the character 'a' as , and the length of the string matched by the character 'b' as . Then we have . If we enumerate , we can determine the value of . Therefore, we can enumerate and check whether there exists an integer that satisfies the above equation.
The time complexity is , and the space complexity is . Here, is the length of the string .
Python3
class Solution:
def patternMatching(self, pattern: str, value: str) -> bool:
def check(la: int, lb: int) -> bool:
i = 0
a, b = "", ""
for c in pattern:
if c == "a":
if a and value[i : i + la] != a:
return False
a = value[i : i + la]
i += la
else:
if b and value[i : i + lb] != b:
return False
b = value[i : i + lb]
i += lb
return a != b
n = len(value)
cnt = Counter(pattern)
if cnt["a"] == 0:
return n % cnt["b"] == 0 and value[: n // cnt["b"]] * cnt["b"] == value
if cnt["b"] == 0:
return n % cnt["a"] == 0 and value[: n // cnt["a"]] * cnt["a"] == value
for la in range(n + 1):
if la * cnt["a"] > n:
break
lb, mod = divmod(n - la * cnt["a"], cnt["b"])
if mod == 0 and check(la, lb):
return True
return False
Java
class Solution {
private String pattern;
private String value;
public boolean patternMatching(String pattern, String value) {
this.pattern = pattern;
this.value = value;
int[] cnt = new int[2];
for (char c : pattern.toCharArray()) {
++cnt[c - 'a'];
}
int n = value.length();
if (cnt[0] == 0) {
return n % cnt[1] == 0 && value.substring(0, n / cnt[1]).repeat(cnt[1]).equals(value);
}
if (cnt[1] == 0) {
return n % cnt[0] == 0 && value.substring(0, n / cnt[0]).repeat(cnt[0]).equals(value);
}
for (int la = 0; la <= n; ++la) {
if (la * cnt[0] > n) {
break;
}
if ((n - la * cnt[0]) % cnt[1] == 0) {
int lb = (n - la * cnt[0]) / cnt[1];
if (check(la, lb)) {
return true;
}
}
}
return false;
}
private boolean check(int la, int lb) {
int i = 0;
String a = null, b = null;
for (char c : pattern.toCharArray()) {
if (c == 'a') {
if (a != null && !a.equals(value.substring(i, i + la))) {
return false;
}
a = value.substring(i, i + la);
i += la;
} else {
if (b != null && !b.equals(value.substring(i, i + lb))) {
return false;
}
b = value.substring(i, i + lb);
i += lb;
}
}
return !a.equals(b);
}
}
C++
class Solution {
public:
bool patternMatching(string pattern, string value) {
int n = value.size();
int cnt[2]{};
for (char c : pattern) {
cnt[c - 'a']++;
}
if (cnt[0] == 0) {
return n % cnt[1] == 0 && repeat(value.substr(0, n / cnt[1]), cnt[1]) == value;
}
if (cnt[1] == 0) {
return n % cnt[0] == 0 && repeat(value.substr(0, n / cnt[0]), cnt[0]) == value;
}
auto check = [&](int la, int lb) {
int i = 0;
string a, b;
for (char c : pattern) {
if (c == 'a') {
if (!a.empty() && a != value.substr(i, la)) {
return false;
}
a = value.substr(i, la);
i += la;
} else {
if (!b.empty() && b != value.substr(i, lb)) {
return false;
}
b = value.substr(i, lb);
i += lb;
}
}
return a != b;
};
for (int la = 0; la <= n; ++la) {
if (la * cnt[0] > n) {
break;
}
if ((n - la * cnt[0]) % cnt[1] == 0) {
int lb = (n - la * cnt[0]) / cnt[1];
if (check(la, lb)) {
return true;
}
}
}
return false;
}
string repeat(string s, int n) {
string ans;
while (n--) {
ans += s;
}
return ans;
}
};
Go
func patternMatching(pattern string, value string) bool {
cnt := [2]int{}
for _, c := range pattern {
cnt[c-'a']++
}
n := len(value)
if cnt[0] == 0 {
return n%cnt[1] == 0 && strings.Repeat(value[:n/cnt[1]], cnt[1]) == value
}
if cnt[1] == 0 {
return n%cnt[0] == 0 && strings.Repeat(value[:n/cnt[0]], cnt[0]) == value
}
check := func(la, lb int) bool {
i := 0
a, b := "", ""
for _, c := range pattern {
if c == 'a' {
if a != "" && value[i:i+la] != a {
return false
}
a = value[i : i+la]
i += la
} else {
if b != "" && value[i:i+lb] != b {
return false
}
b = value[i : i+lb]
i += lb
}
}
return a != b
}
for la := 0; la <= n; la++ {
if la*cnt[0] > n {
break
}
if (n-la*cnt[0])%cnt[1] == 0 {
lb := (n - la*cnt[0]) / cnt[1]
if check(la, lb) {
return true
}
}
}
return false
}
TypeScript
function patternMatching(pattern: string, value: string): boolean {
const cnt: number[] = [0, 0];
for (const c of pattern) {
cnt[c === 'a' ? 0 : 1]++;
}
const n = value.length;
if (cnt[0] === 0) {
return n % cnt[1] === 0 && value.slice(0, (n / cnt[1]) | 0).repeat(cnt[1]) === value;
}
if (cnt[1] === 0) {
return n % cnt[0] === 0 && value.slice(0, (n / cnt[0]) | 0).repeat(cnt[0]) === value;
}
const check = (la: number, lb: number) => {
let i = 0;
let a = '';
let b = '';
for (const c of pattern) {
if (c === 'a') {
if (a && a !== value.slice(i, i + la)) {
return false;
}
a = value.slice(i, (i += la));
} else {
if (b && b !== value.slice(i, i + lb)) {
return false;
}
b = value.slice(i, (i += lb));
}
}
return a !== b;
};
for (let la = 0; la <= n; ++la) {
if (la * cnt[0] > n) {
break;
}
if ((n - la * cnt[0]) % cnt[1] === 0) {
const lb = ((n - la * cnt[0]) / cnt[1]) | 0;
if (check(la, lb)) {
return true;
}
}
}
return false;
}
Swift
class Solution {
private var pattern: String = ""
private var value: String = ""
func patternMatching(_ pattern: String, _ value: String) -> Bool {
self.pattern = pattern
self.value = value
var cnt = [Int](repeating: 0, count: 2)
for c in pattern {
cnt[Int(c.asciiValue! - Character("a").asciiValue!)] += 1
}
let n = value.count
if cnt[0] == 0 {
return n % cnt[1] == 0 && String(repeating: String(value.prefix(n / cnt[1])), count: cnt[1]) == value
}
if cnt[1] == 0 {
return n % cnt[0] == 0 && String(repeating: String(value.prefix(n / cnt[0])), count: cnt[0]) == value
}
for la in 0...n {
if la * cnt[0] > n {
break
}
if (n - la * cnt[0]) % cnt[1] == 0 {
let lb = (n - la * cnt[0]) / cnt[1]
if check(la, lb) {
return true
}
}
}
return false
}
private func check(_ la: Int, _ lb: Int) -> Bool {
var a: String? = nil
var b: String? = nil
var index = value.startIndex
for c in pattern {
if c == "a" {
let end = value.index(index, offsetBy: la)
if let knownA = a {
if knownA != value[index..<end] {
return false
}
} else {
a = String(value[index..<end])
}
index = end
} else {
let end = value.index(index, offsetBy: lb)
if let knownB = b {
if knownB != value[index..<end] {
return false
}
} else {
b = String(value[index..<end])
}
index = end
}
}
return a != b
}
}