291. Word Pattern II
leetcode medium
Task
Дан шаблон и строка s, вернуть true, если строка s соответствует шаблону.
Строка s соответствует шаблону, если существует биективное отображение отдельных символов на непустые строки так, что если каждый символ в шаблоне заменить на строку, которой он отображается, то результирующая строка будет равна s. Биективное отображение означает, что ни два символа не отображаются на одну и ту же строку, и ни один символ не отображается на две разные строки.
Пример:
Input: pattern = "abab", s = "redblueredblue"
Output: true
Explanation: One possible mapping is as follows:
'a' -> "red"
'b' -> "blue"
C# solution
matched/originalusing System;
using System.Collections.Generic;
public class Solution {
public bool WordPatternMatch(string pattern, string s) {
var symbolMap = new Dictionary<char, string>();
var wordSet = new HashSet<string>();
return IsMatch(s, 0, pattern, 0, symbolMap, wordSet);
}
private bool IsMatch(string s, int sIndex, string pattern, int pIndex,
Dictionary<char, string> symbolMap, HashSet<string> wordSet) {
if (pIndex == pattern.Length) {
return sIndex == s.Length;
}
char symbol = pattern[pIndex];
if (symbolMap.ContainsKey(symbol)) {
string word = symbolMap[symbol];
if (!s.Substring(sIndex).StartsWith(word)) {
return false;
}
return IsMatch(s, sIndex + word.Length, pattern, pIndex + 1, symbolMap, wordSet);
}
for (int k = sIndex + 1; k <= s.Length; k++) {
string newWord = s.Substring(sIndex, k - sIndex);
if (wordSet.Contains(newWord)) {
continue;
}
symbolMap[symbol] = newWord;
wordSet.Add(newWord);
if (IsMatch(s, k, pattern, pIndex + 1, symbolMap, wordSet)) {
return true;
}
symbolMap.Remove(symbol);
wordSet.Remove(newWord);
}
return false;
}
}C++ solution
auto-draft, review before submit#include <bits/stdc++.h>
using namespace std;
// Auto-generated C++ draft from the C# solution. Review containers, LINQ and helper types before submit.
class Solution {
public:
public bool WordPatternMatch(string pattern, string s) {
var symbolMap = new unordered_map<char, string>();
var wordSet = new HashSet<string>();
return IsMatch(s, 0, pattern, 0, symbolMap, wordSet);
}
private bool IsMatch(string s, int sIndex, string pattern, int pIndex,
unordered_map<char, string> symbolMap, HashSet<string> wordSet) {
if (pIndex == pattern.size()) {
return sIndex == s.size();
}
char symbol = pattern[pIndex];
if (symbolMap.count(symbol)) {
string word = symbolMap[symbol];
if (!s.Substring(sIndex).StartsWith(word)) {
return false;
}
return IsMatch(s, sIndex + word.size(), pattern, pIndex + 1, symbolMap, wordSet);
}
for (int k = sIndex + 1; k <= s.size(); k++) {
string newWord = s.Substring(sIndex, k - sIndex);
if (wordSet.Contains(newWord)) {
continue;
}
symbolMap[symbol] = newWord;
wordSet.push_back(newWord);
if (IsMatch(s, k, pattern, pIndex + 1, symbolMap, wordSet)) {
return true;
}
symbolMap.Remove(symbol);
wordSet.Remove(newWord);
}
return false;
}
}Java solution
matched/originalimport java.util.HashMap;
import java.util.HashSet;
public class Solution {
public boolean wordPatternMatch(String pattern, String s) {
HashMap<Character, String> symbolMap = new HashMap<>();
HashSet<String> wordSet = new HashSet<>();
return isMatch(s, 0, pattern, 0, symbolMap, wordSet);
}
private boolean isMatch(String s, int sIndex, String pattern, int pIndex,
HashMap<Character, String> symbolMap, HashSet<String> wordSet) {
if (pIndex == pattern.length()) {
return sIndex == s.length();
}
char symbol = pattern.charAt(pIndex);
if (symbolMap.containsKey(symbol)) {
String word = symbolMap.get(symbol);
if (!s.startsWith(word, sIndex)) {
return false;
}
return isMatch(s, sIndex + word.length(), pattern, pIndex + 1, symbolMap, wordSet);
}
for (int k = sIndex + 1; k <= s.length(); k++) {
String newWord = s.substring(sIndex, k);
if (wordSet.contains(newWord)) {
continue;
}
symbolMap.put(symbol, newWord);
wordSet.add(newWord);
if (isMatch(s, k, pattern, pIndex + 1, symbolMap, wordSet)) {
return true;
}
symbolMap.remove(symbol);
wordSet.remove(newWord);
}
return false;
}
}JavaScript solution
matched/originalclass Solution {
wordPatternMatch(pattern, s) {
const symbolMap = new Map();
const wordSet = new Set();
return this.isMatch(s, 0, pattern, 0, symbolMap, wordSet);
}
isMatch(s, sIndex, pattern, pIndex, symbolMap, wordSet) {
if (pIndex
if (pIndex === pattern.length) {
return sIndex === s.length;
}
const symbol = pattern[pIndex];
if (symbolMap.has(symbol)) {
const word = symbolMap.get(symbol);
if (!s.startsWith(word, sIndex)) {
return false;
}
return this.isMatch(s, sIndex + word.length, pattern, pIndex + 1, symbolMap, wordSet);
}
for (let k = sIndex + 1; k <= s.length; k++) {
const newWord = s.substring(sIndex, k);
if (wordSet.has(newWord)) {
continue;
}
symbolMap.set(symbol, newWord);
wordSet.add(newWord);
if (this.isMatch(s, k, pattern, pIndex + 1, symbolMap, wordSet)) {
return true;
}
symbolMap.delete(symbol);
wordSet.delete(newWord);
}
return false;
}
}Python solution
matched/originalclass Solution:
def wordPatternMatch(self, pattern: str, s: str) -> bool:
symbol_map = {}
word_set = set()
return self.is_match(s, 0, pattern, 0, symbol_map, word_set)
def is_match(self, s, s_index, pattern, p_index, symbol_map, word_set):
if p_index == len(pattern):
return s_index == len(s)
symbol = pattern[p_index]
if symbol in symbol_map:
word = symbol_map[symbol]
if not s.startswith(word, s_index):
return False
return self.is_match(s, s_index + len(word), pattern, p_index + 1, symbol_map, word_set)
for k in range(s_index + 1, len(s) + 1):
new_word = s[s_index:k]
if new_word in word_set:
continue
symbol_map[symbol] = new_word
word_set.add(new_word)
if self.is_match(s, k, pattern, p_index + 1, symbol_map, word_set):
return True
del symbol_map[symbol]
word_set.remove(new_word)
return FalseGo solution
matched/originalpackage main
func wordPatternMatch(pattern string, s string) bool {
symbolMap := make(map[rune]string)
wordSet := make(map[string]bool)
return isMatch(s, 0, pattern, 0, symbolMap, wordSet)
}
func isMatch(s string, sIndex int, pattern string, pIndex int,
symbolMap map[rune]string, wordSet map[string]bool) bool {
if pIndex == len(pattern) {
return sIndex == len(s)
}
symbol := rune(pattern[pIndex])
if word, ok := symbolMap[symbol]; ok {
if !startsWith(s, sIndex, word) {
return false
}
return isMatch(s, sIndex+len(word), pattern, pIndex+1, symbolMap, wordSet)
}
for k := sIndex + 1; k <= len(s); k++ {
newWord := s[sIndex:k]
if wordSet[newWord] {
continue
}
symbolMap[symbol] = newWord
wordSet[newWord] = true
if isMatch(s, k, pattern, pIndex+1, symbolMap, wordSet) {
return true
}
delete(symbolMap, symbol)
delete(wordSet, newWord)
}
return false
}
func startsWith(s string, sIndex int, word string) bool {
if len(s)-sIndex < len(word) {
return false
}
for i := 0; i < len(word); i++ {
if s[sIndex+i] != word[i] {
return false
}
}
return true
}Explanation
Algorithm
Инициализация структур данных и определение рекурсивной функции:
Создайте хеш-таблицу symbolMap для отображения символов шаблона на подстроки строки s.
Создайте множество wordSet для хранения уникальных подстрок строки s, которые были отображены на символ.
Определите рекурсивную функцию isMatch, принимающую индексы в строке s (sIndex) и в шаблоне (pIndex), чтобы определить, соответствует ли строка s шаблону.
Рекурсивная проверка соответствия:
Базовый случай: если pIndex равно длине шаблона, верните true, если sIndex равно длине строки s; иначе верните false.
Получите символ из шаблона по индексу pIndex.
Если символ уже ассоциирован с подстрокой, проверьте, совпадают ли следующие символы в строке s с этой подстрокой. Если нет, верните false. Если совпадают, вызовите isMatch для следующего символа в шаблоне.
Отображение новых подстрок:
Если символ новый, попробуйте сопоставить его с новыми подстроками строки s, начиная с sIndex и до конца строки.
Для каждой новой подстроки проверьте, существует ли она уже в `
😎