diff --git a/10. Regular Expression Matching/10. Regular Expression Matching.csproj b/10. Regular Expression Matching/10. Regular Expression Matching.csproj new file mode 100644 index 0000000..061f772 --- /dev/null +++ b/10. Regular Expression Matching/10. Regular Expression Matching.csproj @@ -0,0 +1,11 @@ + + + + Exe + net10.0 + _10._Regular_Expression_Matching + enable + enable + + + diff --git a/10. Regular Expression Matching/Program.cs b/10. Regular Expression Matching/Program.cs new file mode 100644 index 0000000..fafea8a --- /dev/null +++ b/10. Regular Expression Matching/Program.cs @@ -0,0 +1,29 @@ +var solution = new Solution(); + +var examples = new (string s, string p, bool expected)[] +{ + ("aa", "a", false), + ("aa", "a*", true), + ("ab", ".*", true), + ("aab", "c*a*b", true), + ("mississippi", "mis*is*p*.", false), + ("mississippi", "mis*is*ip*.", true), + ("aaa", "a*a", true), + ("aaa", "ab*a*c*a", true), + ("ab", ".*c", false), + ("", "c*", true), + ("abcd", "d*", false), + ("", "", true), + ("a", ".", true), + ("", "a*", true), + ("aa", "b*a*", true), + ("a", "ab*", true), + ("abcaaaaaaabaabcabac", ".*ab.a.*a*a*.*b*b*", true), + ("", "a*b*", true), +}; + +foreach (var example in examples) +{ + var result = solution.IsMatch(example.s, example.p); + Console.WriteLine($"s = \"{example.s}\", p = \"{example.p}\" => {result} (expected {example.expected})"); +} diff --git a/10. Regular Expression Matching/Solution.cs b/10. Regular Expression Matching/Solution.cs new file mode 100644 index 0000000..d8bda39 --- /dev/null +++ b/10. Regular Expression Matching/Solution.cs @@ -0,0 +1,59 @@ +public class Solution +{ + public bool IsMatch(string s, string p) => IsMatch(null, s, p); + + private bool IsMatch(char? prev, ReadOnlySpan str, ReadOnlySpan pattern) + { + if (pattern.Length == 0 && str.Length == 0) + return true; + if (str.Length == 0) + { + if (CanBeEmpty(pattern)) + return true; + return false; + } + if (pattern.Length == 0) + return false; + var sym = str[0]; + var p = pattern[0]; + // раскрытая звёздочка + var pSymOrDot = p == '*' ? prev : p; // превращаем звёздочку в символ или точку + // ожидаемый текущий символ, конкретный + var pSym = pSymOrDot == '.' ? sym : pSymOrDot; + + + // следующий символ * + if (pattern.Length > 1 && pattern[1] == '*') + { + var match = false; + var i = 0; + do + { + match |= IsMatch(i > 0 ? p : prev, str[i..], pattern[2..]); + if (match || i == str.Length || str[i] != p && p != '.') + break; + i++; + } + while (i <= str.Length); + return match; + } + else if (sym != pSym) + { + return false; + } + else + { + return IsMatch(pSymOrDot, str[1..], pattern[1..]); + } + } + + private bool CanBeEmpty(ReadOnlySpan pattern) + { + if (pattern.Length % 2 == 1) + return false; + for (var i = 1; i < pattern.Length; i += 2) + if (pattern[i] != '*') + return false; + return true; + } +} \ No newline at end of file diff --git a/Leetcode.sln b/Leetcode.sln index 4b3f035..c25662f 100644 --- a/Leetcode.sln +++ b/Leetcode.sln @@ -177,6 +177,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "347. Top K Frequent Element EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "5. Longest Palindromic Substring", "5. Longest Palindromic Substring\5. Longest Palindromic Substring.csproj", "{8F972144-7AF8-4860-9A9F-AB56D40D7C67}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "10. Regular Expression Matching", "10. Regular Expression Matching\10. Regular Expression Matching.csproj", "{0A6CECBE-AD75-4829-AAB2-D6D29EEECEB5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1231,6 +1233,18 @@ Global {8F972144-7AF8-4860-9A9F-AB56D40D7C67}.Release|x64.Build.0 = Release|Any CPU {8F972144-7AF8-4860-9A9F-AB56D40D7C67}.Release|x86.ActiveCfg = Release|Any CPU {8F972144-7AF8-4860-9A9F-AB56D40D7C67}.Release|x86.Build.0 = Release|Any CPU + {0A6CECBE-AD75-4829-AAB2-D6D29EEECEB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0A6CECBE-AD75-4829-AAB2-D6D29EEECEB5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A6CECBE-AD75-4829-AAB2-D6D29EEECEB5}.Debug|x64.ActiveCfg = Debug|Any CPU + {0A6CECBE-AD75-4829-AAB2-D6D29EEECEB5}.Debug|x64.Build.0 = Debug|Any CPU + {0A6CECBE-AD75-4829-AAB2-D6D29EEECEB5}.Debug|x86.ActiveCfg = Debug|Any CPU + {0A6CECBE-AD75-4829-AAB2-D6D29EEECEB5}.Debug|x86.Build.0 = Debug|Any CPU + {0A6CECBE-AD75-4829-AAB2-D6D29EEECEB5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0A6CECBE-AD75-4829-AAB2-D6D29EEECEB5}.Release|Any CPU.Build.0 = Release|Any CPU + {0A6CECBE-AD75-4829-AAB2-D6D29EEECEB5}.Release|x64.ActiveCfg = Release|Any CPU + {0A6CECBE-AD75-4829-AAB2-D6D29EEECEB5}.Release|x64.Build.0 = Release|Any CPU + {0A6CECBE-AD75-4829-AAB2-D6D29EEECEB5}.Release|x86.ActiveCfg = Release|Any CPU + {0A6CECBE-AD75-4829-AAB2-D6D29EEECEB5}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE