mirror of
https://hub.njuu.cf/TheAlgorithms/C-Plus-Plus.git
synced 2023-10-11 13:05:55 +08:00
a2970af4c4
* Feat: Abbreivation problem (abbreviation.cpp), topic: Dynamic Programming. * Spelling correction * Spelling Mistakes * Refactoring code * updating DIRECTORY.md * clang-format and clang-tidy fixes for232d4f5e
* clang-format and clang-tidy fixes for232d4f5e
* Documentation and renaming variable * adding a comment * adding a comment * Re-documentation * Re-documentation * Re-documentation * Update dynamic_programming/abbreviation.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update dynamic_programming/abbreviation.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update dynamic_programming/abbreviation.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Varaible type-checks * Update dynamic_programming/abbreviation.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * clang-format and clang-tidy fixes for8f5a50be
* Varaible type-checks * Markdown correction * Comment Modification Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal <halfpacho@gmail.com>
195 lines
7.6 KiB
C++
195 lines
7.6 KiB
C++
/**
|
|
* @file
|
|
* @brief Implementation of
|
|
* [Abbrievation](https://www.hackerrank.com/challenges/abbr/problem)
|
|
*
|
|
* @details
|
|
* Given two strings, `a` and `b`, determine if it's possible to make `a` equal
|
|
* to `b` You can perform the following operations on the string `a`:
|
|
* 1. Capitalize zero or more of `a`'s lowercase letters.
|
|
* 2. Delete all of the remaining lowercase letters in `a`.
|
|
*
|
|
* ### Algorithm
|
|
* The idea is in the problem statement itself: iterate through characters of
|
|
* string `a` and `b` (for character indexes `i` and `j` respectively):
|
|
* 1. If `a[i]` and `b[j]` are equal, then move to next position
|
|
* 2. If `a[i]` is lowercase of `b[j]`, then explore two possibilities:
|
|
* a. Capitalize `a[i]` or
|
|
* b. Skip `a[i]`
|
|
* 3. If the `a[i]` is not uppercase, just discard that character, else return
|
|
* `false`
|
|
*
|
|
* Time Complexity: (O(|a|*|b|)) where `|a|` => length of string `a`
|
|
* @author [Ashish Daulatabad](https://github.com/AshishYUO)
|
|
*/
|
|
|
|
#include <cassert> /// for `assert`
|
|
#include <iostream> /// for IO operations
|
|
#include <string> /// for `std::string` library
|
|
#include <vector> /// for `std::vector` STL library
|
|
/**
|
|
* @namespace dynamic_programming
|
|
* @brief Dynamic Programming Algorithms
|
|
*/
|
|
namespace dynamic_programming {
|
|
/**
|
|
* @namespace abbreviation
|
|
* @brief Functions for
|
|
* [Abbreviation](https://www.hackerrank.com/challenges/abbr/problem)
|
|
* implementation
|
|
*/
|
|
namespace abbreviation {
|
|
/**
|
|
* @brief
|
|
* Recursive Dynamic Programming function
|
|
* @details
|
|
* Returns whether `s` can be converted to `t` with following rules:
|
|
* a. Capitalize zero or more of a's lowercase letters from string `s`
|
|
* b. remove all other lowercase letters from string `s`
|
|
* @param memo To store the result
|
|
* @param visited boolean to check if the result is already computed
|
|
* @param str given string, which might not be abbreivated
|
|
* @param result resultant abbreivated string
|
|
* @param str_idx index for string `str`, helpful for transitions
|
|
* @param result_idx index for string `result`, helpful for transitions
|
|
* @returns `false` if string `str` cannot be converted to `result`
|
|
* @returns `true` if string `str` can be converted to `result`
|
|
*/
|
|
bool abbreviation_recursion(std::vector<std::vector<bool>> *memo,
|
|
std::vector<std::vector<bool>> *visited,
|
|
const std::string &str, const std::string &result,
|
|
uint32_t str_idx = 0, uint32_t result_idx = 0) {
|
|
bool ans = memo->at(str_idx).at(result_idx);
|
|
if (str_idx == str.size() && result_idx == result.size()) {
|
|
return true;
|
|
} else if (str_idx == str.size() && result_idx != result.size()) {
|
|
// result `t` is not converted, return false
|
|
return false;
|
|
} else if (!visited->at(str_idx).at(result_idx)) {
|
|
/**
|
|
* `(str[i] == result[j])`: if str char at position i is equal to
|
|
* `result` char at position j, then s character is a capitalized one,
|
|
* move on to next character `str[i] - 32 == result[j]`:
|
|
* if `str[i]` character is lowercase of `result[j]` then explore two
|
|
* possibilites:
|
|
* 1. convert it to capitalized letter and move both to next pointer
|
|
* `(i + 1, j + 1)`
|
|
* 2. Discard the character `(str[i])` and move to next char `(i + 1,
|
|
* j)`
|
|
*/
|
|
if (str[str_idx] == result[result_idx]) {
|
|
ans = abbreviation_recursion(memo, visited, str, result,
|
|
str_idx + 1, result_idx + 1);
|
|
} else if (str[str_idx] - 32 == result[result_idx]) {
|
|
ans = abbreviation_recursion(memo, visited, str, result,
|
|
str_idx + 1, result_idx + 1) ||
|
|
abbreviation_recursion(memo, visited, str, result,
|
|
str_idx + 1, result_idx);
|
|
} else {
|
|
// if `str[i]` is uppercase, then cannot be converted, return
|
|
// `false`
|
|
// else `str[i]` is lowercase, only option is to discard this
|
|
// character
|
|
if (str[str_idx] >= 'A' && str[str_idx] <= 'Z') {
|
|
ans = false;
|
|
} else {
|
|
ans = abbreviation_recursion(memo, visited, str, result,
|
|
str_idx + 1, result_idx);
|
|
}
|
|
}
|
|
}
|
|
(*memo)[str_idx][result_idx] = ans;
|
|
(*visited)[str_idx][result_idx] = true;
|
|
return (*memo)[str_idx][result_idx];
|
|
}
|
|
/**
|
|
* @brief
|
|
* Iterative Dynamic Programming function
|
|
* @details
|
|
* Returns whether `s` can be converted to `t` with following rules:
|
|
* a. Capitalize zero or more of s's lowercase letters from string `s`
|
|
* b. remove all other lowercase letters from string `s`
|
|
* Note: The transition states for iterative is similar to recursive as well
|
|
* @param str given string, which might not be abbreivated
|
|
* @param result resultant abbreivated string
|
|
* @returns `false` if string `str` cannot be converted to `result`
|
|
* @returns `true` if string `str` can be converted to `result`
|
|
*/
|
|
bool abbreviation(const std::string &str, const std::string &result) {
|
|
std::vector<std::vector<bool>> memo(
|
|
str.size() + 1, std::vector<bool>(result.size() + 1, false));
|
|
|
|
for (uint32_t i = 0; i <= str.size(); ++i) {
|
|
memo[i][0] = true;
|
|
}
|
|
for (uint32_t i = 1; i <= result.size(); ++i) {
|
|
memo[0][i] = false;
|
|
}
|
|
for (uint32_t i = 1; i <= str.size(); ++i) {
|
|
for (uint32_t j = 1; j <= result.size(); ++j) {
|
|
if (str[i - 1] == result[j - 1]) {
|
|
memo[i][j] = memo[i - 1][j - 1];
|
|
} else if (str[i - 1] - 32 == result[j - 1]) {
|
|
memo[i][j] = (memo[i - 1][j - 1] || memo[i - 1][j]);
|
|
} else {
|
|
if (str[i - 1] >= 'A' && str[i - 1] <= 'Z') {
|
|
memo[i][j] = false;
|
|
} else {
|
|
memo[i][j] = memo[i - 1][j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return memo.back().back();
|
|
}
|
|
} // namespace abbreviation
|
|
} // namespace dynamic_programming
|
|
|
|
/**
|
|
* @brief Self test-implementations
|
|
* @returns void
|
|
*/
|
|
static void test() {
|
|
std::string s = "daBcd", t = "ABC";
|
|
std::vector<std::vector<bool>> memo(s.size() + 1,
|
|
std::vector<bool>(t.size() + 1, false)),
|
|
visited(s.size() + 1, std::vector<bool>(t.size() + 1, false));
|
|
|
|
assert(dynamic_programming::abbreviation::abbreviation_recursion(
|
|
&memo, &visited, s, t) == true);
|
|
assert(dynamic_programming::abbreviation::abbreviation(s, t) == true);
|
|
s = "XXVVnDEFYgYeMXzWINQYHAQKKOZEYgSRCzLZAmUYGUGILjMDET";
|
|
t = "XXVVDEFYYMXWINQYHAQKKOZEYSRCLZAUYGUGILMDETQVWU";
|
|
memo = std::vector<std::vector<bool>>(
|
|
s.size() + 1, std::vector<bool>(t.size() + 1, false));
|
|
|
|
visited = std::vector<std::vector<bool>>(
|
|
s.size() + 1, std::vector<bool>(t.size() + 1, false));
|
|
|
|
assert(dynamic_programming::abbreviation::abbreviation_recursion(
|
|
&memo, &visited, s, t) == false);
|
|
assert(dynamic_programming::abbreviation::abbreviation(s, t) == false);
|
|
|
|
s = "DRFNLZZVHLPZWIupjwdmqafmgkg";
|
|
t = "DRFNLZZVHLPZWI";
|
|
|
|
memo = std::vector<std::vector<bool>>(
|
|
s.size() + 1, std::vector<bool>(t.size() + 1, false));
|
|
|
|
visited = std::vector<std::vector<bool>>(
|
|
s.size() + 1, std::vector<bool>(t.size() + 1, false));
|
|
|
|
assert(dynamic_programming::abbreviation::abbreviation_recursion(
|
|
&memo, &visited, s, t) == true);
|
|
assert(dynamic_programming::abbreviation::abbreviation(s, t) == true);
|
|
}
|
|
|
|
/**
|
|
* @brief Main function
|
|
* @returns 0 on exit
|
|
*/
|
|
int main() {
|
|
test(); // run self-test implementations
|
|
return 0;
|
|
}
|