Wildcard Pattern Matching in Linear Time and Constant Space
Last Updated :
05 Dec, 2024
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));
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.
Similar Reads
What is Pattern Searching ?
Pattern searching in Data Structures and Algorithms (DSA) is a fundamental concept that involves searching for a specific pattern or sequence of elements within a given data structure. This technique is commonly used in string matching algorithms to find occurrences of a particular pattern within a
5 min read
Introduction to Pattern Searching - Data Structure and Algorithm Tutorial
Pattern searching is an algorithm that involves searching for patterns such as strings, words, images, etc. We use certain algorithms to do the search process. The complexity of pattern searching varies from algorithm to algorithm. They are very useful when performing a search in a database. The Pat
15+ min read
Naive algorithm for Pattern Searching
Given text string with length n and a pattern with length m, the task is to prints all occurrences of pattern in text. Note: You may assume that n > m. Examples:Â Input: Â text = "THIS IS A TEST TEXT", pattern = "TEST"Output: Pattern found at index 10 Input: Â text = Â "AABAACAADAABAABA", pattern =
6 min read
Rabin-Karp Algorithm for Pattern Searching
Given a text T[0. . .n-1] and a pattern P[0. . .m-1], write a function search(char P[], char T[]) that prints all occurrences of P[] present in T[] using Rabin Karp algorithm. You may assume that n > m. Examples: Input: T[] = "THIS IS A TEST TEXT", P[] = "TEST"Output: Pattern found at index 10 In
15 min read
KMP Algorithm for Pattern Searching
Given two strings txt and pat, the task is to return all indices of occurrences of pat within txt. Examples: Input: txt = "abcab", pat = "ab"Output: [0, 3]Explanation: The string "ab" occurs twice in txt, first occurrence starts from index 0 and second from index 3. Input: txt= "aabaacaadaabaaba", p
14 min read
Z algorithm (Linear time pattern searching Algorithm)
This algorithm efficiently locates all instances of a specific pattern within a text in linear time. If the length of the text is "n" and the length of the pattern is "m," then the total time taken is O(m + n), with a linear auxiliary space. It is worth noting that the time and auxiliary space of th
13 min read
Finite Automata algorithm for Pattern Searching
Given a text txt[0..n-1] and a pattern pat[0..m-1], write a function search(char pat[], char txt[]) that prints all occurrences of pat[] in txt[]. You may assume that n > m.Examples: Input: txt[] = "THIS IS A TEST TEXT" pat[] = "TEST" Output: Pattern found at index 10 Input: txt[] = "AABAACAADAAB
13 min read
Boyer Moore Algorithm for Pattern Searching
Pattern searching is an important problem in computer science. When we do search for a string in a notepad/word file, browser, or database, pattern searching algorithms are used to show the search results. A typical problem statement would be-Â " Given a text txt[0..n-1] and a pattern pat[0..m-1] wh
15+ min read
Aho-Corasick Algorithm for Pattern Searching
Given an input text and an array of k words, arr[], find all occurrences of all words in the input text. Let n be the length of text and m be the total number of characters in all words, i.e. m = length(arr[0]) + length(arr[1]) + ... + length(arr[k-1]). Here k is total numbers of input words. Exampl
15+ min read
ÂÂkasaiâs Algorithm for Construction of LCP array from Suffix Array
Background Suffix Array : A suffix array is a sorted array of all suffixes of a given string. Let the given string be "banana". 0 banana 5 a1 anana Sort the Suffixes 3 ana2 nana ----------------> 1 anana 3 ana alphabetically 0 banana 4 na 4 na 5 a 2 nanaThe suffix array for "banana" :suffix[] = {
15+ min read