diff --git a/DIRECTORY.md b/DIRECTORY.md index 9b059be70..4bd8db0e8 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -11,6 +11,7 @@ * [Subarray Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/subarray_sum.cpp) * [Subset Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/subset_sum.cpp) * [Sudoku Solve](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/sudoku_solve.cpp) + * [Wildcard Matching](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/wildcard_matching.cpp) ## Bit Manipulation * [Count Of Set Bits](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/bit_manipulation/count_of_set_bits.cpp) diff --git a/backtracking/wildcard_matching.cpp b/backtracking/wildcard_matching.cpp new file mode 100644 index 000000000..d9163a41b --- /dev/null +++ b/backtracking/wildcard_matching.cpp @@ -0,0 +1,155 @@ +/** + * @file + * @brief Implementation of the [Wildcard + * Matching](https://www.geeksforgeeks.org/wildcard-pattern-matching/) problem. + * @details + * Given a matching string and a pattern, implement wildcard pattern + * matching with support for `?` and `*`. `?` matches any single character. + * `*` matches any sequence of characters (including the empty sequence). + * The matching should cover the entire matching string (not partial). The task + * is to determine if the pattern matches with the matching string + * @author [Swastika Gupta](https://github.com/Swastyy) + */ + +#include /// for assert +#include /// for IO operations +#include /// for std::vector + +/** + * @namespace backtracking + * @brief Backtracking algorithms + */ +namespace backtracking { +/** + * @namespace wildcard_matching + * @brief Functions for the [Wildcard + * Matching](https://www.geeksforgeeks.org/wildcard-pattern-matching/) problem. + */ +namespace wildcard_matching { +/** + * @brief The main function implements if pattern can be matched with given + * string + * @param s is the given matching string + * @param p is the given pattern + * @param pos1 is the starting index + * @param pos2 is the last index + * @returns 1 if pattern matches with matching string otherwise 0 + */ +std::vector> dpTable(1000, std::vector(1000, -1)); +bool wildcard_matching(std::string s, std::string p, uint32_t pos1, + uint32_t pos2) { + uint32_t n = s.length(); + uint32_t m = p.length(); + // matching is successfull if both strings are done + if (pos1 == n && pos2 == m) { + return true; + } + + // matching is unsuccessfull if pattern is not finished but matching string + // is + if (pos1 != n && pos2 == m) { + return false; + } + + // all the remaining characters of patterns must be * inorder to match with + // finished string + if (pos1 == n && pos2 != m) { + while (pos2 < m && p[pos2] == '*') { + pos2++; + } + + return pos2 == m; + } + + // if already calculted for these positions + if (dpTable[pos1][pos2] != -1) { + return dpTable[pos1][pos2]; + } + + // if the characters are same just go ahead in both the string + if (s[pos1] == p[pos2]) { + return dpTable[pos1][pos2] = + wildcard_matching(s, p, pos1 + 1, pos2 + 1); + } + + else { + // can only single character + if (p[pos2] == '?') { + return dpTable[pos1][pos2] = + wildcard_matching(s, p, pos1 + 1, pos2 + 1); + } + // have choice either to match one or more charcters + else if (p[pos2] == '*') { + return dpTable[pos1][pos2] = + wildcard_matching(s, p, pos1, pos2 + 1) || + wildcard_matching(s, p, pos1 + 1, pos2); + } + // not possible to match + else { + return dpTable[pos1][pos2] = 0; + } + } +} + +} // namespace wildcard_matching +} // namespace backtracking + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // 1st test + std::cout << "1st test "; + std::string matching1 = "baaabab"; + std::string pattern1 = "*****ba*****ab"; + assert(backtracking::wildcard_matching::wildcard_matching(matching1, + pattern1, 0, 0) == + 1); // here the pattern matches with given string + std::cout << "passed" << std::endl; + + // 2nd test + std::cout << "2nd test "; + std::string matching2 = "baaabab"; + std::string pattern2 = "ba*****ab"; + assert(backtracking::wildcard_matching::wildcard_matching(matching2, + pattern2, 0, 0) == + 1); // here the pattern matches with given string + std::cout << "passed" << std::endl; + + // 3rd test + std::cout << "3rd test "; + std::string matching3 = "baaabab"; + std::string pattern3 = "ba*ab"; + assert(backtracking::wildcard_matching::wildcard_matching(matching3, + pattern3, 0, 0) == + 1); // here the pattern matches with given string + std::cout << "passed" << std::endl; + + // 4th test + std::cout << "4th test "; + std::string matching4 = "baaabab"; + std::string pattern4 = "a*ab"; + assert(backtracking::wildcard_matching::wildcard_matching(matching4, + pattern4, 0, 0) == + 1); // here the pattern matches with given string + std::cout << "passed" << std::endl; + + // 5th test + std::cout << "5th test "; + std::string matching5 = "baaabab"; + std::string pattern5 = "aa?ab"; + assert(backtracking::wildcard_matching::wildcard_matching(matching5, + pattern5, 0, 0) == + 1); // here the pattern matches with given string + std::cout << "passed" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +}