面试题 16.18. 模式匹配
May 17, 2024 · View on GitHub
题目描述
你有两个字符串,即pattern和value。 pattern字符串由字母"a"和"b"组成,用于描述字符串中的模式。例如,字符串"catcatgocatgo"匹配模式"aabab"(其中"cat"是"a","go"是"b"),该字符串也匹配像"a"、"ab"和"b"这样的模式。但需注意"a"和"b"不能同时表示相同的字符串。编写一个方法判断value字符串是否匹配pattern字符串。
示例 1:
输入: pattern = "abba", value = "dogcatcatdog" 输出: true
示例 2:
输入: pattern = "abba", value = "dogcatcatfish" 输出: false
示例 3:
输入: pattern = "aaaa", value = "dogcatcatdog" 输出: false
示例 4:
输入: pattern = "abba", value = "dogdogdogdog" 输出: true 解释: "a"="dogdog",b="",反之也符合规则
提示:
0 <= len(pattern) <= 10000 <= len(value) <= 1000- 你可以假设
pattern只包含字母"a"和"b",value仅包含小写字母。
解法
方法一:枚举
我们先统计出模式串 中 'a' 和 'b' 的个数,分别为 和 。记字符串 的长度为 。
如果 ,说明模式串中只包含字符 'b',那么我们需要判断 是否是 的倍数,以及 是否可以分割成 个长度为 的子串,且这些子串都相同。如果不满足,直接返回 即可。
如果 ,说明模式串中只包含字符 'a',那么我们需要判断 是否是 的倍数,以及 是否可以分割成 个长度为 的子串,且这些子串都相同。如果不满足,直接返回 即可。
接下来,我们记字符 'a' 所匹配的字符串的长度 ,字符 'b' 所匹配的字符串的长度 。那么有 。如果我们枚举 ,就可以知道 的值了。因此我们可以枚举 ,只需要判断是否存在一个整数 ,满足上述等式即可。
时间复杂度 ,空间复杂度 。其中 为字符串 的长度。
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
}
}