Open In App

Wildcard Pattern Matching in Linear Time and Constant Space

Last Updated : 05 Dec, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

Given two strings ‘str‘ and a wildcard pattern ‘pattern‘ of length n and m respectively, the task is to return ‘1’ if the wildcard pattern is matched with str else return ‘0‘. All characters of the string str and pattern always belong to the alphanumeric characters.

  • ‘?’ – matches any single character 
  • ‘*’ – Matches any sequence of characters (including the empty sequence)

Pre-requisite: Dynamic Programming | Wildcard Pattern Matching

Examples:

Input: pattern = “ba*a?”, str = “baaabab”
Output: 1
Explanation: Replace ‘*’ with “aab” and ‘?’ with ‘b’.

Input: pattern = “a*ab”, str = “baaabab”
Output: 0
Explanation: Because in string pattern character ‘a’ at first position, pattern and str can’t be matched.

Approach For Wildcard Pattern Matching in Linear Time and Constant Space

The ‘?‘ character is straightforward as it matches any single character, which means whenever ‘?’ appears in the pattern, it corresponds to any character in the input string. The ‘*’ character, however, can represent any sequence of characters, including the empty sequence. This introduces complexity because ‘*’ can potentially match zero, one, two, or more characters.

The main idea to solve this problem efficiently is to use a greedy backtracking approach instead of trying all possible expansions of ‘*’. By using two pointers to traverse the string and the pattern, our solution would records the position of the last ‘*’ encountered and the corresponding position in the string. Initially, ‘*’ is assumed to match zero characters, but if a mismatch occurs later, the solution backtracks and assumes ‘*’ matches one more character, and continues this process iteratively. This greedy strategy reduces unnecessary checks and computations, making the solution more efficient. After traversing the string, our solution would make sure that any remaining characters in the pattern are all ‘*’, which can match an empty sequence.

Step-by-Step Implementation:

  • Initialize pointers for the string and pattern, and variables to store the positions of ‘*’ and the last matched position.
  • Traverse through the string and pattern:
    • If characters match or the pattern has ‘?’, move both pointers.
    • If the pattern has ‘*’, store the position and proceed with the next character in the pattern.
    • If a mismatch happens and there was a ‘*’, backtrack by incrementing the last stored position in the string.
  • Check if remaining characters in the pattern are all ‘*’.
  • Return true if matched, otherwise false.
C++
// C++ Programe to Wildcard Pattern Matching
// in Linear Time and Constant Space
#include <bits/stdc++.h>
using namespace std;

// Function to check if a string matches a given pattern
int isMatch(string s, string p) {
    int sLen = s.length(), pLen = p.length();
    int sIdx = 0, pIdx = 0;
    int starIdx = -1, sTmpIdx = -1;

    // Iterate through the string and pattern
    while (sIdx < sLen) {

        // If the pattern character matches the string
        // character or the pattern character is '?'
        if (pIdx < pLen && (p[pIdx] == '?' || p[pIdx] == s[sIdx])) {
            ++sIdx;
            ++pIdx;
        }

        // If the pattern character is '*'
        else if (pIdx < pLen && p[pIdx] == '*') {

            // Record the position of '*' and the current
            // string index
            starIdx = pIdx;
            sTmpIdx = sIdx;
            ++pIdx;
        }

        // If there is no match and no previous '*' to
        // backtrack to
        else if (starIdx == -1) {
            return 0;
        }

        // If there is a previous '*' to backtrack to
        else {

            // Backtrack to the last '*'
            pIdx = starIdx + 1;
            sIdx = sTmpIdx + 1;
            sTmpIdx = sIdx;
        }
    }

    // Ensure remaining characters in the pattern are all
    // '*'
    for (int i = pIdx; i < pLen; i++) {
        if (p[i] != '*') {
            return 0;
        }
    }
    return 1;
}

int main() {
    string pattern = "ba*a?";
    string str = "baaabab";

    cout << isMatch(str, pattern);

    return 0;
}
Java
// Java Program to Wildcard Pattern Matching in Linear Time
// and Constant Space
class GfG {
    static int isMatch(String s, String p) {
        int sLen = s.length(), pLen = p.length();
        int sIdx = 0, pIdx = 0;
        int starIdx = -1, sTmpIdx = -1;

        // Iterate through the string and pattern
        while (sIdx < sLen) {

            // If the pattern character matches the string
            // character or the pattern character is '?'
            if (pIdx < pLen
                && (p.charAt(pIdx) == '?'
                    || p.charAt(pIdx) == s.charAt(sIdx))) {
                ++sIdx;
                ++pIdx;
            }

            // If the pattern character is '*'
            else if (pIdx < pLen && p.charAt(pIdx) == '*') {

                // Record the position of '*' and the
                // current string index
                starIdx = pIdx;
                sTmpIdx = sIdx;
                ++pIdx;
            }

            // If there is no match and no previous '*' to
            // backtrack to
            else if (starIdx == -1) {
                return 0;
            }

            // If there is a previous '*' to backtrack to
            else {

                // Backtrack to the last '*'
                pIdx = starIdx + 1;
                sIdx = sTmpIdx + 1;
                sTmpIdx = sIdx;
            }
        }

        // Ensure remaining characters in the pattern are
        // all
        // '*'
        for (int i = pIdx; i < pLen; i++) {
            if (p.charAt(i) != '*') {
                return 0;
            }
        }
        return 1;
    }
   	public static void main(String[] args) {
        String pattern = "ba*a?";
        String str = "baaabab";

        System.out.println(isMatch(str, pattern));
    }
}
Python
# Python Program to Wildcard Pattern Matching in
# Linear Time and Constant Space
def isMatch(s, p):
    s_len, p_len = len(s), len(p)
    s_idx, p_idx = 0, 0
    star_idx, s_tmp_idx = -1, -1

    # Iterate through the string and pattern
    while s_idx < s_len:

        # If the pattern character matches the string
        # character or the pattern character is '?'
        if p_idx < p_len and (p[p_idx] == '?' or \
                              p[p_idx] == s[s_idx]):
            s_idx += 1
            p_idx += 1

        # If the pattern character is '*'
        elif p_idx < p_len and p[p_idx] == '*':

            # Record the position of '*'
            # and the current
            # string index
            star_idx = p_idx
            s_tmp_idx = s_idx
            p_idx += 1

        # If there is no match and no previous '*' to
        # backtrack to
        elif star_idx == -1:
            return 0

        # If there is a previous '*' to backtrack to
        else:

            # Backtrack to the last '*'
            p_idx = star_idx + 1
            s_idx = s_tmp_idx + 1
            s_tmp_idx = s_idx

    # Ensure remaining characters in the pattern are all
    # '*'
    for i in range(p_idx, p_len):
        if p[i] != '*':
            return 0
    return 1


if __name__ == "__main__":
    pattern = "ba*a?"
    string = "baaabab"
    print(isMatch(string, pattern))
C#
// C# Program to Wildcard Pattern Matching in
// Linear Time and Constant Space
using System;

class GfG {
    static int isMatch(string s, string p) {
        int sLen = s.Length, pLen = p.Length;
        int sIdx = 0, pIdx = 0;
        int starIdx = -1, sTmpIdx = -1;

        // Iterate through the string and pattern
        while (sIdx < sLen) {

            // If the pattern character matches the string
            // character or the pattern character is '?'
            if (pIdx < pLen
                && (p[pIdx] == '?' || p[pIdx] == s[sIdx])) {
                ++sIdx;
                ++pIdx;
            }

            // If the pattern character is '*'
            else if (pIdx < pLen && p[pIdx] == '*') {

                // Record the position of '*' and the
                // current string index
                starIdx = pIdx;
                sTmpIdx = sIdx;
                ++pIdx;
            }

            // If there is no match and no previous '*' to
            // backtrack to
            else if (starIdx == -1) {
                return 0;
            }

            // If there is a previous '*' to backtrack to
            else {

                // Backtrack to the last '*'
                pIdx = starIdx + 1;
                sIdx = sTmpIdx + 1;
                sTmpIdx = sIdx;
            }
        }

        // Ensure remaining characters in the pattern are
        // all
        // '*'
        for (int i = pIdx; i < pLen; i++) {
            if (p[i] != '*') {
                return 0;
            }
        }
        return 1;
    }
  
   	static void Main(string[] args) {
        string pattern = "ba*a?";
        string str = "baaabab";
        Console.WriteLine(isMatch(str, pattern));
    }
}
JavaScript
// JavaScript Program to Wildcard Pattern Matching in Linear
// Time and Constant Space
function isMatch(s, p) {

    let sLen = s.length, pLen = p.length;
    let sIdx = 0, pIdx = 0;
    let starIdx = -1, sTmpIdx = -1;

    // Iterate through the string and pattern
    while (sIdx < sLen) {

        // If the pattern character matches the string
        // character or the pattern character is '?'
        if (pIdx < pLen
            && (p[pIdx] === "?" || p[pIdx] === s[sIdx])) {
            ++sIdx;
            ++pIdx;
        }

        // If the pattern character is '*'
        else if (pIdx < pLen && p[pIdx] === "*") {

            // Record the position of '*' and the current
            // string index
            starIdx = pIdx;
            sTmpIdx = sIdx;
            ++pIdx;
        }

        // If there is no match and no previous '*' to
        // backtrack to
        else if (starIdx === -1) {
            return 0;
        }

        // If there is a previous '*' to backtrack to
        else {

            // Backtrack to the last '*'
            pIdx = starIdx + 1;
            sIdx = sTmpIdx + 1;
            sTmpIdx = sIdx;
        }
    }

    // Ensure remaining characters in the pattern are all
    // '*'
    for (let i = pIdx; i < pLen; i++) {
        if (p[i] !== "*") {
            return 0;
        }
    }
    return 1;
}

const pattern = "ba*a?";
const str = "baaabab";
console.log(isMatch(str, pattern));

Output
1

Time complexity: O(s+p), where s and p are lengths of the input string and the pattern correspondingly
Auxiliary Space: O(1) since it’s a constant space solution.



Next Article

Similar Reads