diff --git a/Dynamic Programming/Scramble String/README.md b/Dynamic Programming/Scramble String/README.md new file mode 100644 index 00000000..f9e14991 --- /dev/null +++ b/Dynamic Programming/Scramble String/README.md @@ -0,0 +1,35 @@ +# Scramble String Problem + +## Description + +The Scramble String problem is to determine whether one string is a scrambled version of another. Given two strings, `s1` and `s2`, we say that `s2` is a scrambled version of `s1` if it can be formed by recursively dividing `s1` into two non-empty substrings and swapping them. + +For example: +- Input: `s1 = "great"`, `s2 = "rgeat"` +- Output: `true` (because "rgeat" is a scrambled version of "great") + +## Problem Requirements + +We need to: +1. Check if two strings contain the same characters. +2. Recursively verify if substrings can be swapped to form the scrambled string. +3. Optimize using memoization to avoid redundant calculations. + +## Solution Approach + +This solution uses **Dynamic Programming** with **Recursion and Memoization**: + +1. **Recursive Check**: + - For each possible split of `s1`, we recursively check: + - If dividing and not swapping substrings forms `s2`, or + - If dividing and swapping substrings forms `s2`. + +2. **Memoization Table**: + - We use a 3D table `memo[i1][i2][len]` to store results of subproblems where: + - `i1` and `i2` are starting indices in `s1` and `s2`. + - `len` is the length of the substrings. + - Each entry in the table can be either `-1` (not calculated), `1` (scramble), or `0` (not a scramble). + +3. **Complexity**: + - **Time Complexity**: `O(N^4)`, where `N` is the length of the string. + - **Space Complexity**: `O(N^3)` due to the memoization table. diff --git a/Dynamic Programming/Scramble String/program.c b/Dynamic Programming/Scramble String/program.c new file mode 100644 index 00000000..3cc87671 --- /dev/null +++ b/Dynamic Programming/Scramble String/program.c @@ -0,0 +1,60 @@ +#include +#include +#include + +#define MAX_LEN 100 + +// Memoization table to store results +int memo[MAX_LEN][MAX_LEN][MAX_LEN]; + +// Helper function to check if two strings have the same characters +bool haveSameCharacters(const char *s1, const char *s2, int len) { + int count[26] = {0}; + for (int i = 0; i < len; i++) { + count[s1[i] - 'a']++; + count[s2[i] - 'a']--; + } + for (int i = 0; i < 26; i++) { + if (count[i] != 0) return false; + } + return true; +} + +// Recursive function with memoization to check if s2 is a scrambled version of s1 +bool isScramble(const char *s1, const char *s2, int i1, int i2, int len) { + if (memo[i1][i2][len] != -1) return memo[i1][i2][len]; + + if (strncmp(s1 + i1, s2 + i2, len) == 0) return memo[i1][i2][len] = 1; + + if (!haveSameCharacters(s1 + i1, s2 + i2, len)) return memo[i1][i2][len] = 0; + + for (int i = 1; i < len; i++) { + if ((isScramble(s1, s2, i1, i2, i) && isScramble(s1, s2, i1 + i, i2 + i, len - i)) || + (isScramble(s1, s2, i1, i2 + len - i, i) && isScramble(s1, s2, i1 + i, i2, len - i))) { + return memo[i1][i2][len] = 1; + } + } + + return memo[i1][i2][len] = 0; +} + +bool isScrambleWrapper(const char *s1, const char *s2) { + int len = strlen(s1); + if (len != strlen(s2)) return false; + + memset(memo, -1, sizeof(memo)); + return isScramble(s1, s2, 0, 0, len); +} + +int main() { + const char *s1 = "great"; + const char *s2 = "rgeat"; + + if (isScrambleWrapper(s1, s2)) { + printf("'%s' is a scrambled version of '%s'\n", s2, s1); + } else { + printf("'%s' is NOT a scrambled version of '%s'\n", s2, s1); + } + + return 0; +}