From 3741b41a8a68c0ddc71a40f37e51a5df088a565d Mon Sep 17 00:00:00 2001 From: ridhishjain Date: Mon, 17 Aug 2020 19:08:14 +0530 Subject: [PATCH] feat: add shortest common super-sequence algorithm (#1030) * main cpp file for shortest common supersequence * fixing reverse function bug * converting c style array to std::vector * removing namespace directives * adding documentation and test cases * namespace declarations * update shortest_common_supersequence.cpp * update shortest_common_supersequence.cpp * Update dynamic_programming/shortest_common_supersequence.cpp Co-authored-by: David Leal * Update dynamic_programming/shortest_common_supersequence.cpp Co-authored-by: David Leal * Update dynamic_programming/shortest_common_supersequence.cpp Co-authored-by: David Leal * update shortest_common_supersequence.cpp * update shortest_common_supersequence.cpp * update shortest_common_supersequence.cpp * Update dynamic_programming/shortest_common_supersequence.cpp Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> * updating DIRECTORY.md Co-authored-by: David Leal Co-authored-by: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- DIRECTORY.md | 1 + .../shortest_common_supersequence.cpp | 179 ++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 dynamic_programming/shortest_common_supersequence.cpp diff --git a/DIRECTORY.md b/DIRECTORY.md index 76fa1154d..0349f7039 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -67,6 +67,7 @@ * [Longest Increasing Subsequence (Nlogn)](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/longest_increasing_subsequence_(nlogn).cpp) * [Matrix Chain Multiplication](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/matrix_chain_multiplication.cpp) * [Searching Of Element In Dynamic Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/searching_of_element_in_dynamic_array.cpp) + * [Shortest Common Supersequence](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/shortest_common_supersequence.cpp) * [Tree Height](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/dynamic_programming/tree_height.cpp) ## Geometry diff --git a/dynamic_programming/shortest_common_supersequence.cpp b/dynamic_programming/shortest_common_supersequence.cpp new file mode 100644 index 000000000..3064359fb --- /dev/null +++ b/dynamic_programming/shortest_common_supersequence.cpp @@ -0,0 +1,179 @@ +/** + * @file + * @brief SCS is a string Z which is the shortest supersequence of strings X and Y (may not be continuous in Z, but order is maintained). + * + * @details + * The idea is to use lookup table method as used in LCS. + * For example: example 1:- + * X: 'ABCXYZ', Y: 'ABZ' then Z will be 'ABCXYZ' (y is not continuous but in order) + * + * For example: example 2:- + * X: 'AGGTAB', Y: 'GXTXAYB' then Z will be 'AGGXTXAYB' + * @author [Ridhish Jain](https://github.com/ridhishjain) + * @see more on [SCS](https://en.wikipedia.org/wiki/Shortest_common_supersequence_problem) + * @see related problem [Leetcode](https://leetcode.com/problems/shortest-common-supersequence/) +*/ + +// header files +#include +#include +#include +#include +#include + +/** + * @namespace dynamic_programming + * @brief Dynamic Programming algorithms +*/ +namespace dynamic_programming { + + /** + * @namespace shortest_common_supersequence + * @brief Shortest Common Super Sequence algorithm + */ + namespace shortest_common_supersequence { + + /** + * Function implementing Shortest Common Super-Sequence algorithm using look-up table method. + * @param str1 first string 'X' + * @param str2 second string 'Y' + * @returns string 'Z', superSequence of X and Y + */ + std::string scs(const std::string &str1, const std::string &str2) { + + // Edge cases + // If either str1 or str2 or both are empty + if(str1.empty() && str2.empty()) { + return ""; + } + else if(str1.empty()) { + return str2; + } + else if(str2.empty()) { + return str1; + } + + // creating lookup table + std::vector > lookup(str1.length() + 1, std::vector (str2.length() + 1, 0)); + + for(int i=1; i <= str1.length(); i++) { + for(int j=1; j <= str2.length(); j++) { + if(str1[i-1] == str2[j-1]) { + lookup[i][j] = lookup[i-1][j-1] + 1; + } + else { + lookup[i][j] = std::max(lookup[i-1][j], lookup[i][j-1]); + } + } + } + + // making supersequence + // i and j are initially pointed towards end of strings + // Super-sequence will be constructed backwards + int i=str1.length(); + int j=str2.length(); + std::string s; + + while(i>0 && j>0) { + + // If the characters at i and j of both strings are same + // We only need to add them once in s + if(str1[i-1] == str2[j-1]) { + s.push_back(str1[i-1]); + i--; + j--; + } + // otherwise we check lookup table for recurrences of characters + else { + if(lookup[i-1][j] > lookup[i][j-1]) { + s.push_back(str1[i-1]); + i--; + } + else { + s.push_back(str2[j-1]); + j--; + } + } + } + + // copying remaining elements + // if j becomes 0 before i + while(i > 0) { + s.push_back(str1[i-1]); + i--; + } + + // if i becomes 0 before j + while(j > 0) { + s.push_back(str2[j-1]); + j--; + } + + // As the super sequence is constructd backwards + // reversing the string before returning gives us the correct output + reverse(s.begin(), s.end()); + return s; + } + } // namespace shortest_common_supersequence +} // namespace dynamic_programming + +/** + * Test Function + * @return void +*/ +static void test() { + // custom input vector + std::vector > scsStrings { + {"ABCXYZ", "ABZ"}, + {"ABZ", "ABCXYZ"}, + {"AGGTAB", "GXTXAYB"}, + {"X", "Y"}, + }; + + // calculated output vector by scs function + std::vector calculatedOutput(4, ""); + int i=0; + for(auto & scsString : scsStrings) { + + calculatedOutput[i] = dynamic_programming::shortest_common_supersequence::scs( + scsString[0], scsString[1] + ); + i++; + } + + // expected output vector acc to problem statement + std::vector expectedOutput { + "ABCXYZ", + "ABCXYZ", + "AGGXTXAYB", + "XY" + }; + + // Testing implementation via assert function + // It will throw error if any of the expected test fails + // Else it will give nothing + for(int i=0; i < scsStrings.size(); i++) { + assert(expectedOutput[i] == calculatedOutput[i]); + } + + std::cout << "All tests passed successfully!\n"; + return; +} + +/** Main function (driver code)*/ +int main() { + // test for implementation + test(); + + // user input + std::string s1, s2; + std::cin >> s1; + std::cin >> s2; + + std::string ans; + + // user output + ans = dynamic_programming::shortest_common_supersequence::scs(s1, s2); + std::cout << ans; + return 0; +}