44. Wildcard Matching

Problem


Tags: String, Dynamic Programming, Greedy, Recursion

Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for '?' and '*' where:

  • '?' Matches any single character.
  • '*' Matches any sequence of characters (including the empty sequence).

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 = "*"
Output: true
Explanation: '*' matches any sequence.

Example 3:

Input: s = "cb", p = "?a"
Output: false
Explanation: '?' matches 'c', but the second letter is 'a', which does not match 'b'.

Constraints:

  • 0 <= s.length, p.length <= 2000
  • s contains only lowercase English letters.
  • p contains only lowercase English letters, '?' or '*'.

Solution

Solution

The most difficult part of this problem is '*', when we meet it, we don't know how many chars we should match.

So, we store a position to "come back" after the current match failed.

Code

C

// 44. Wildcard Matching (12/10/54169)
// Runtime: 8 ms (67.76%) Memory: 5.79 MB (76.50%) 

bool isMatch(char* str, char* pat) {
    int str_len = strlen(str), pat_len = strlen(pat);
    int str_idx = 0, pat_idx = 0;
    int str_idx_retry = 0, pat_idx_retry = 0;

    while (str_idx < str_len || pat_idx < pat_len) {
        // printf("---\nstr: %s\npat: %s\n", str + str_idx, pat + pat_idx);
        if (pat_idx < pat_len) {
            if (pat[pat_idx] == '*') {
                pat_idx_retry = pat_idx;
                str_idx_retry = str_idx + 1;
                pat_idx++;
                continue;
            }
            else if (pat[pat_idx] == '?' && str_idx < str_len) {
                str_idx++, pat_idx++;
                continue;
            }
            else if (str[str_idx] == pat[pat_idx]) {
                str_idx++, pat_idx++;
                continue;
            }
        }

        if (str_idx_retry > 0 && str_idx_retry <= str_len) {
            str_idx = str_idx_retry;
            pat_idx = pat_idx_retry;
            continue;
        }

        return false;
    }

    return true;
}

GO

// 44. Wildcard Matching (10/24/54169)
// Runtime: 8 ms (79.38%) Memory: 2.87 MB (89.38%) 

func isMatch(target string, pattern string) bool {
	target_idx, pattern_idx := 0, 0
	target_idx_retry, pattern_idx_retry := 0, 0

	for pattern_idx < len(pattern) || target_idx < len(target) {
		if pattern_idx < len(pattern) {
			c := pattern[pattern_idx]
			switch c {
			case '?':
				if target_idx < len(target) {
					pattern_idx++
					target_idx++
					continue
				}
			case '*':
				pattern_idx_retry = pattern_idx
				target_idx_retry = target_idx + 1
				pattern_idx++
				continue
			default:
				if target_idx < len(target) && target[target_idx] == c {
					pattern_idx++
					target_idx++
					continue
				}
			}
		}
        
		if 0 < target_idx_retry && target_idx_retry <= len(target) {
			pattern_idx = pattern_idx_retry
			target_idx = target_idx_retry
			continue
		}
		
		return false
	}

	return true
}