|
| 1 | +/* |
| 2 | + * Wildcard Matching Algorithm |
| 3 | + * |
| 4 | + * Description: |
| 5 | + * Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for: |
| 6 | + * - '?' Matches any single character |
| 7 | + * - '*' Matches any sequence of characters (including the empty sequence) |
| 8 | + * |
| 9 | + * The matching should cover the entire input string (not partial). |
| 10 | + * |
| 11 | + * Approach: |
| 12 | + * We use recursion with the following rules: |
| 13 | + * 1. If both string and pattern are exhausted, return true. |
| 14 | + * 2. If pattern is exhausted but string remains, return false. |
| 15 | + * 3. If string is exhausted but pattern remains, check if remaining characters in pattern are all '*'. |
| 16 | + * 4. If characters match OR pattern has '?', move both indices back by 1. |
| 17 | + * 5. If pattern has '*', try two options: |
| 18 | + * - Treat '*' as matching one character (move string index back by 1, keep pattern index same). |
| 19 | + * - Treat '*' as matching empty (move pattern index back by 1, keep string index same). |
| 20 | + * |
| 21 | + * Time Complexity: Exponential in worst case (O(2^(m+n))) without memoization, |
| 22 | + * since '*' can branch into two recursive calls. |
| 23 | + * With DP memoization, this can be optimized to O(m*n). |
| 24 | + * |
| 25 | + * Space Complexity: O(m+n) recursion stack (without memoization). |
| 26 | + */ |
| 27 | + |
| 28 | +#include <bits/stdc++.h> |
| 29 | +using namespace std; |
| 30 | + |
| 31 | +class Solution { |
| 32 | +public: |
| 33 | + bool solve(int index1, int index2, string &text, string &pattern) { |
| 34 | + // Both strings exhausted |
| 35 | + if (index1 < 0 && index2 < 0) return true; |
| 36 | + |
| 37 | + // Pattern exhausted, text remains |
| 38 | + if (index2 < 0 && index1 >= 0) return false; |
| 39 | + |
| 40 | + // Text exhausted, check if remaining pattern is all '*' |
| 41 | + if (index1 < 0 && index2 >= 0) { |
| 42 | + for (int i = 0; i <= index2; i++) { |
| 43 | + if (pattern[i] != '*') return false; |
| 44 | + } |
| 45 | + return true; |
| 46 | + } |
| 47 | + |
| 48 | + // Characters match OR pattern has '?' |
| 49 | + if (text[index1] == pattern[index2] || pattern[index2] == '?') { |
| 50 | + return solve(index1 - 1, index2 - 1, text, pattern); |
| 51 | + } |
| 52 | + |
| 53 | + // If pattern has '*': try both possibilities |
| 54 | + if (pattern[index2] == '*') { |
| 55 | + return solve(index1 - 1, index2, text, pattern) // '*' matches one char |
| 56 | + || solve(index1, index2 - 1, text, pattern); // '*' matches empty |
| 57 | + } |
| 58 | + |
| 59 | + return false; |
| 60 | + } |
| 61 | + |
| 62 | + bool isMatch(string s, string p) { |
| 63 | + int n1 = s.size(); |
| 64 | + int n2 = p.size(); |
| 65 | + return solve(n1 - 1, n2 - 1, s, p); |
| 66 | + } |
| 67 | +}; |
| 68 | + |
| 69 | +// Main function with test cases |
| 70 | +int main() { |
| 71 | + Solution sol; |
| 72 | + |
| 73 | + // Test Case 1 |
| 74 | + cout << "Test Case 1:" << endl; |
| 75 | + string s1 = "aa", p1 = "a"; |
| 76 | + cout << "String: " << s1 << ", Pattern: " << p1 << endl; |
| 77 | + cout << "Match: " << (sol.isMatch(s1, p1) ? "true" : "false") << endl << endl; // false |
| 78 | + |
| 79 | + // Test Case 2 |
| 80 | + cout << "Test Case 2:" << endl; |
| 81 | + string s2 = "aa", p2 = "*"; |
| 82 | + cout << "String: " << s2 << ", Pattern: " << p2 << endl; |
| 83 | + cout << "Match: " << (sol.isMatch(s2, p2) ? "true" : "false") << endl << endl; // true |
| 84 | + |
| 85 | + // Test Case 3 |
| 86 | + cout << "Test Case 3:" << endl; |
| 87 | + string s3 = "cb", p3 = "?a"; |
| 88 | + cout << "String: " << s3 << ", Pattern: " << p3 << endl; |
| 89 | + cout << "Match: " << (sol.isMatch(s3, p3) ? "true" : "false") << endl << endl; // false |
| 90 | + |
| 91 | + // Test Case 4 |
| 92 | + cout << "Test Case 4:" << endl; |
| 93 | + string s4 = "adceb", p4 = "*a*b"; |
| 94 | + cout << "String: " << s4 << ", Pattern: " << p4 << endl; |
| 95 | + cout << "Match: " << (sol.isMatch(s4, p4) ? "true" : "false") << endl << endl; // true |
| 96 | + |
| 97 | + // Test Case 5 |
| 98 | + cout << "Test Case 5:" << endl; |
| 99 | + string s5 = "acdcb", p5 = "a*c?b"; |
| 100 | + cout << "String: " << s5 << ", Pattern: " << p5 << endl; |
| 101 | + cout << "Match: " << (sol.isMatch(s5, p5) ? "true" : "false") << endl << endl; // false |
| 102 | + |
| 103 | + return 0; |
| 104 | +} |
0 commit comments