diff --git a/regx/readme.md b/regx/readme.md new file mode 100644 index 0000000..e9ad173 --- /dev/null +++ b/regx/readme.md @@ -0,0 +1,41 @@ +10. Regular Expression Matching +Hard + +Given an input string s and a pattern p, implement regular expression matching with support for '.' and '*' where: + + '.' Matches any single character.​​​​ + '*' Matches zero or more of the preceding element. + +The matching should cover the entire input string (not partial). + + + +Example 1: + +Input: s = "aa", p = "a" +Output: false +Explanation: "a" does not match the entire string "aa". + +Example 2: + +Input: s = "aa", p = "a*" +Output: true +Explanation: '*' means zero or more of the preceding element, 'a'. Therefore, by repeating 'a' once, it becomes "aa". + +Example 3: + +Input: s = "ab", p = ".*" +Output: true +Explanation: ".*" means "zero or more (*) of any character (.)". + + + +Constraints: + + 1 <= s.length <= 20 + 1 <= p.length <= 30 + s contains only lowercase English letters. + p contains only lowercase English letters, '.', and '*'. + It is guaranteed for each appearance of the character '*', there will be a previous valid character to match. + + diff --git a/regx/regx.go b/regx/regx.go new file mode 100644 index 0000000..d128ba2 --- /dev/null +++ b/regx/regx.go @@ -0,0 +1,35 @@ +package regx + +func isCharMatch(text, pattern string) bool { + return pattern[0] == '.' || pattern[0] == text[0] +} + +func matchStar(text, pattern string) bool { + for { + switch { + case isMatch(text, pattern[2:]): + return true + case text == "" || !isCharMatch(text, pattern): + return false + default: + text = text[1:] + } + } +} + +func isMatch(text, pattern string) bool { + switch { + case pattern == "": + return text == "" + case len(pattern) >= 2 && pattern[1] == '*': + return matchStar(text, pattern) + case text != "" && isCharMatch(text, pattern): + return isMatch(text[1:], pattern[1:]) + } + + return false +} + +func IsMatch(text, pattern string) bool { + return isMatch(text, pattern) +} diff --git a/regx/regx_test.go b/regx/regx_test.go new file mode 100644 index 0000000..c768eba --- /dev/null +++ b/regx/regx_test.go @@ -0,0 +1,52 @@ +package regx_test + +import ( + "testing" + + "git.jxs.me/leetgo/regx" + "github.com/stretchr/testify/require" +) + +func TestEmpty(t *testing.T) { + require.True(t, regx.IsMatch("", "")) +} + +func TestSingleMatch(t *testing.T) { + require.True(t, regx.IsMatch("a", "a")) +} + +func TestSingleNonMatch(t *testing.T) { + require.False(t, regx.IsMatch("b", "a")) +} + +func TestMultiMatch(t *testing.T) { + require.True(t, regx.IsMatch("aba", "aba")) +} + +func TestMultiNonMatch(t *testing.T) { + require.False(t, regx.IsMatch("abca", "abac")) +} + +func TestWildMatch(t *testing.T) { + require.True(t, regx.IsMatch("hello", "h.ll.")) +} + +func TestWildNonMatch(t *testing.T) { + require.False(t, regx.IsMatch("hello", "hall.")) +} + +func TestManyMatch(t *testing.T) { + require.True(t, regx.IsMatch("greeet", "gre*t")) +} + +func TestManyMisMatch(t *testing.T) { + require.True(t, regx.IsMatch("greet", "gre*a*t")) +} + +func TestWildcardManyMatch(t *testing.T) { + require.True(t, regx.IsMatch("anything", ".*")) +} + +func TestWildcardNonGreedyMatch(t *testing.T) { + require.True(t, regx.IsMatch("bbba", ".*a")) +}