-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
/
longest_common_string.cpp
159 lines (145 loc) · 5.25 KB
/
longest_common_string.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/**
* @file
* @brief contains the definition of the function ::longest_common_string_length
* @details
* the function ::longest_common_string_length computes the length
* of the longest common string which can be created of two input strings
* by removing characters from them
*
* @author [Nikhil Arora](https://github.com/nikhilarora068)
* @author [Piotr Idzik](https://github.com/vil02)
*/
#include <cassert> /// for assert
#include <iostream> /// for std::cout
#include <string> /// for std::string
#include <utility> /// for std::move
#include <vector> /// for std::vector
/**
* @brief computes the length of the longest common string created from input
* strings
* @details has O(str_a.size()*str_b.size()) time and memory complexity
* @param string_a first input string
* @param string_b second input string
* @returns the length of the longest common string which can be strated from
* str_a and str_b
*/
std::size_t longest_common_string_length(const std::string& string_a,
const std::string& string_b) {
const auto size_a = string_a.size();
const auto size_b = string_b.size();
std::vector<std::vector<std::size_t>> sub_sols(
size_a + 1, std::vector<std::size_t>(size_b + 1, 0));
const auto limit = static_cast<std::size_t>(-1);
for (std::size_t pos_a = size_a - 1; pos_a != limit; --pos_a) {
for (std::size_t pos_b = size_b - 1; pos_b != limit; --pos_b) {
if (string_a[pos_a] == string_b[pos_b]) {
sub_sols[pos_a][pos_b] = 1 + sub_sols[pos_a + 1][pos_b + 1];
} else {
sub_sols[pos_a][pos_b] = std::max(sub_sols[pos_a + 1][pos_b],
sub_sols[pos_a][pos_b + 1]);
}
}
}
return sub_sols[0][0];
}
/**
* @brief represents single example inputs and expected output of the function
* ::longest_common_string_length
*/
struct TestCase {
const std::string string_a;
const std::string string_b;
const std::size_t common_string_len;
TestCase(std::string string_a, std::string string_b,
const std::size_t in_common_string_len)
: string_a(std::move(string_a)),
string_b(std::move(string_b)),
common_string_len(in_common_string_len) {}
};
/**
* @return example data used in the tests of ::longest_common_string_length
*/
std::vector<TestCase> get_test_cases() {
return {TestCase("", "", 0),
TestCase("ab", "ab", 2),
TestCase("ab", "ba", 1),
TestCase("", "xyz", 0),
TestCase("abcde", "ace", 3),
TestCase("BADANA", "ANADA", 3),
TestCase("BADANA", "CANADAS", 3),
TestCase("a1a234a5aaaa6", "A1AAAA234AAA56AAAAA", 6),
TestCase("123x", "123", 3),
TestCase("12x3x", "123", 3),
TestCase("1x2x3x", "123", 3),
TestCase("x1x2x3x", "123", 3),
TestCase("x12x3x", "123", 3)};
}
/**
* @brief checks the function ::longest_common_string_length agains example data
* @param test_cases list of test cases
* @tparam type representing a list of test cases
*/
template <typename TestCases>
static void test_longest_common_string_length(const TestCases& test_cases) {
for (const auto& cur_tc : test_cases) {
assert(longest_common_string_length(cur_tc.string_a, cur_tc.string_b) ==
cur_tc.common_string_len);
}
}
/**
* @brief checks if the function ::longest_common_string_length returns the same
* result when its argument are flipped
* @param test_cases list of test cases
* @tparam type representing a list of test cases
*/
template <typename TestCases>
static void test_longest_common_string_length_is_symmetric(
const TestCases& test_cases) {
for (const auto& cur_tc : test_cases) {
assert(longest_common_string_length(cur_tc.string_b, cur_tc.string_a) ==
cur_tc.common_string_len);
}
}
/**
* @brief reverses a given string
* @param in_str input string
* @return the string in which the characters appear in the reversed order as in
* in_str
*/
std::string reverse_str(const std::string& in_str) {
return {in_str.rbegin(), in_str.rend()};
}
/**
* @brief checks if the function ::longest_common_string_length returns the same
* result when its inputs are reversed
* @param test_cases list of test cases
* @tparam type representing a list of test cases
*/
template <typename TestCases>
static void test_longest_common_string_length_for_reversed_inputs(
const TestCases& test_cases) {
for (const auto& cur_tc : test_cases) {
assert(longest_common_string_length(reverse_str(cur_tc.string_a),
reverse_str(cur_tc.string_b)) ==
cur_tc.common_string_len);
}
}
/**
* @brief runs all tests for ::longest_common_string_length funcion
*/
static void tests() {
const auto test_cases = get_test_cases();
assert(test_cases.size() > 0);
test_longest_common_string_length(test_cases);
test_longest_common_string_length_is_symmetric(test_cases);
test_longest_common_string_length_for_reversed_inputs(test_cases);
std::cout << "All tests have successfully passed!\n";
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
tests();
return 0;
}