-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstring_permutation_dup.cpp
170 lines (157 loc) · 4.06 KB
/
string_permutation_dup.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
160
161
162
163
164
165
166
167
168
169
170
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
#include <unordered_set>
#include <unordered_map>
#include <format>
#include <chrono>
static void generatePermutations1(std::string& str, std::string& buffer, std::unordered_set<std::string>& uniques)
{
if(buffer.size() == str.size())
{
uniques.insert(buffer);
return;
}
for(std::size_t i = 0; i < str.size(); ++i)
{
if(!str[i]) continue;
buffer.push_back(str[i]);
str[i] = 0;
generatePermutations1(str, buffer, uniques);
str[i] = buffer.back();
buffer.pop_back();
}
}
// Solution no 1
static std::vector<std::string> generatePermutations1(const std::string_view str)
{
std::vector<std::string> permutations;
std::string buffer;
std::string copyStr { str };
std::unordered_set<std::string> uniques;
generatePermutations1(copyStr, buffer, uniques);
for(const auto& value : uniques)
permutations.push_back(std::move(value));
return permutations;
}
static constexpr std::size_t getNFactorial(std::size_t n)
{
std::size_t value = 1;
while(n > 1)
{
value *= n;
--n;
}
return value;
}
// Solution no 2 (faster than Solution no 1)
static std::vector<std::string> generatePermutations2(const std::string_view str)
{
std::size_t nfact = getNFactorial(str.size());
std::vector<std::string> permutations;
std::unordered_set<std::string> uniques;
std::string copyStr { str };
while(nfact)
{
std::next_permutation(copyStr.begin(), copyStr.end());
uniques.insert(copyStr);
--nfact;
}
for(const auto& value : uniques)
permutations.push_back(std::move(value));
return permutations;
}
static void generatePermutations3(std::unordered_map<char, std::size_t>& freqTable,
std::size_t n,
std::string& buffer,
std::vector<std::string>& permutations)
{
if(buffer.size() == n)
{
permutations.push_back(buffer);
return;
}
for(auto& pair : freqTable)
{
if(pair.second > 0)
{
pair.second -= 1;
buffer.push_back(pair.first);
generatePermutations3(freqTable, n, buffer, permutations);
buffer.pop_back();
pair.second += 1;
}
}
}
static std::unordered_map<char, std::size_t> buildFreqTable(const std::string_view str)
{
std::unordered_map<char, std::size_t> map;
for(const auto& ch : str)
map[ch] += 1;
return map;
}
// Solution no 3 (faster than solution no 1 and 2 both)
static std::vector<std::string> generatePermutations3(const std::string_view str)
{
std::unordered_map<char, std::size_t> freqTable = buildFreqTable(str);
std::string buffer;
std::vector<std::string> permutations;
generatePermutations3(freqTable, str.size(), buffer, permutations);
return permutations;
}
struct Solution1
{
std::vector<std::string> operator()(const std::string_view str)
{
return generatePermutations1(str);
}
};
struct Solution2
{
std::vector<std::string> operator()(const std::string_view str)
{
return generatePermutations2(str);
}
};
struct Solution3
{
std::vector<std::string> operator()(const std::string_view str)
{
return generatePermutations3(str);
}
};
template<typename Sol>
static void runGeneratePermutations(const std::string_view str)
{
std::cout << "Input: " << str << "\n";
auto start = std::chrono::steady_clock::now();
auto permutations = Sol { } (str);
auto end = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(end - start).count();
std::cout << "Permutation count: " << permutations.size() << "\n";
std::cout << "Time taken: " << elapsed << " ms\n";
#ifdef DUMP
for(std::size_t index = 0; const auto& permutation : permutations)
std::cout << std::format("[{}] {}", index++, permutation) << "\n";
#endif
}
static void run(const std::string_view str)
{
static std::size_t runCount = 0;
++runCount;
std::cout << "---------RUN: " << runCount << " ----------\n";
std::cout << "**Solution no 1**\n";
runGeneratePermutations<Solution1>(str);
std::cout << "**Solution no 2**\n";
runGeneratePermutations<Solution2>(str);
std::cout << "**Solution no 3**\n";
runGeneratePermutations<Solution3>(str);
}
int main()
{
run("hell");
run("HelooW");
run("HelooWrrd");
return 0;
}