diff --git a/include/0005_DynamicProgramming/0007_DecodeWays.h b/include/0005_DynamicProgramming/0007_DecodeWays.h new file mode 100644 index 0000000..2003209 --- /dev/null +++ b/include/0005_DynamicProgramming/0007_DecodeWays.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +using namespace std; + +/* +Pattern 1 +Linear Recurrence + +Description +Let 1 maps to 'A', 2 maps to 'B', ..., 26 to 'Z'.Given a digit sequence, count the number of possible decodings of the given digit sequence. + +Consider the input string "123".There are three valid ways to decode it : +"ABC" : The grouping is(1, 2, 3) -> 'A', 'B', 'C' +"AW" : The grouping is(1, 23) -> 'A', 'W' +"LC" : The grouping is(12, 3) -> 'L', 'C' +Note : Groupings that contain invalid codes(e.g., "0" by itself or numbers greater than "26") are not allowed. +For instance, the string "230" is invalid because "0" cannot stand alone, and "30" is greater than "26", so it cannot represent any letter.The task is to find the total number of valid ways to decode a given string. +*/ + +namespace DecodeWays +{ + class DynamicProgramming + { + private: + int CountWaysRecursiveHelper(string& digits, size_t index); + public: + int RecursiveCountWays(string digits); + int DpCountways(string digits); + }; +} \ No newline at end of file diff --git a/source/0005_DynamicProgramming/0007_DecodeWays.cc b/source/0005_DynamicProgramming/0007_DecodeWays.cc new file mode 100644 index 0000000..180fd5f --- /dev/null +++ b/source/0005_DynamicProgramming/0007_DecodeWays.cc @@ -0,0 +1,61 @@ +#include "../../include/0005_DynamicProgramming/0007_DecodeWays.h" + +namespace DecodeWays +{ + int DynamicProgramming::CountWaysRecursiveHelper(string& digits, size_t index) + { + size_t digitsLength = digits.size(); + + // Base case: If the end of the string is reached, return 1 as it signifies a valid decoding. + if (index >= digitsLength) + { + return 1; + } + + int ways = 0; + + // Single digit decoding: check if current digit is not '0'. + if (digits[index] != '0') + { + ways = this->CountWaysRecursiveHelper(digits, index + 1); + } + + // Two digit decoding: check if next two digits are valid. + if ((index + 1 < digitsLength) && ((digits[index] == '1' && digits[index + 1] <= '9') || (digits[index] == '2' && digits[index + 1] <= '6'))) + { + ways += this->CountWaysRecursiveHelper(digits, index + 2); + } + return ways; + } + + int DynamicProgramming::RecursiveCountWays(string digits) + { + return this->CountWaysRecursiveHelper(digits, 0); + } + + int DynamicProgramming::DpCountways(string digits) + { + size_t digitsLength = digits.size(); + + vector dp(digitsLength + 1, 0); + + dp[digitsLength] = 1; + + for (int index = digitsLength - 1; index >= 0; index--) + { + // Single digit decoding: check if current digit is not '0'. + if (digits[index] != '0') + { + dp[index] = dp[index + 1]; + } + + // Two digit decoding: check if next two digits are valid. + if ((index + 1 < digitsLength) && ((digits[index] == '1' && digits[index + 1] <= '9') || (digits[index] == '2' && digits[index + 1] <= '6'))) + { + dp[index] += dp[index + 2]; + } + } + + return dp[0]; + } +} \ No newline at end of file diff --git a/source/0005_DynamicProgramming/CMakeLists.txt b/source/0005_DynamicProgramming/CMakeLists.txt index 2f793df..c8a87c5 100644 --- a/source/0005_DynamicProgramming/CMakeLists.txt +++ b/source/0005_DynamicProgramming/CMakeLists.txt @@ -6,6 +6,7 @@ set(0005DYNAMICPROGRAMMING_SOURCES 0004_MinimumCostClimbingStairs.cc 0005_HouseRobber1.cc 0006_HouseRobber2.cc + 0007_DecodeWays.cc ) diff --git a/test/0005_DynamicProgramming/0007_DecodeWaysTest.cc b/test/0005_DynamicProgramming/0007_DecodeWaysTest.cc new file mode 100644 index 0000000..2196520 --- /dev/null +++ b/test/0005_DynamicProgramming/0007_DecodeWaysTest.cc @@ -0,0 +1,47 @@ +#include +#include "../../include/0005_DynamicProgramming/0007_DecodeWays.h" + +namespace DecodeWays +{ + TEST(DecodeWays, RecursionTest01) + { + // Arrange + DynamicProgramming dp; + string digits = "121"; + int expectedWaysCount = 3; + + // Act + int actualWaysCount = dp.RecursiveCountWays(digits); + + // Assert + ASSERT_EQ(expectedWaysCount, actualWaysCount); + } + + TEST(DecodeWays, DpTest01) + { + // Arrange + DynamicProgramming dp; + string digits = "121"; + int expectedWaysCount = 3; + + // Act + int actualWaysCount = dp.DpCountways(digits); + + // Assert + ASSERT_EQ(expectedWaysCount, actualWaysCount); + } + + TEST(DecodeWays, DpTestInvalidInput) + { + // Arrange + DynamicProgramming dp; + string digits = "230"; + int expectedWaysCount = 0; + + // Act + int actualWaysCount = dp.DpCountways(digits); + + // Assert + ASSERT_EQ(expectedWaysCount, actualWaysCount); + } +} \ No newline at end of file diff --git a/test/0005_DynamicProgramming/CMakeLists.txt b/test/0005_DynamicProgramming/CMakeLists.txt index f6361cb..2e44016 100644 --- a/test/0005_DynamicProgramming/CMakeLists.txt +++ b/test/0005_DynamicProgramming/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable( 0004_MinimumCostClimbingStairsTest.cc 0005_HouseRobber1Test.cc 0006_HouseRobber2Test.cc + 0007_DecodeWaysTest.cc )