LYY ~ 匆匆相遇匆匆去,再相逢时是故人。
理论参考:
Efficiently Enumerating the Subsets of a Set
借鉴博客:
代码实现:
#include<iostream>
#include<string>
#include<set>
#include <cassert>
using namespace std;
// 十进制转二进制理解原理;
string numTobinary(int n) {
string str;
while (n / 2) {
str = to_string(n % 2) + str;
n /= 2;
}
str = to_string(n) + str; // 二进制的最后一位(个)位数;
while (str.length() < 8) {
str = "0" + str;
}
return str;
}
// 2 ^ 64 是上限,故 只能处理母串长度 <64 的情况;
string binaryStringGenerator(int strLenAsExp, int runs) {
cout << endl << runs + 1 << " runs:" << endl;
string str(strLenAsExp,'2'); // 随便赋给非0、非1的字符即可
//cout << endl << "str = " << str << endl;
for (int exponent = 0; exponent < strLenAsExp; exponent++) {
// 通过输出查看原理;
cout << endl;
cout << "runs = " << runs << "\t\t" << numTobinary(runs) << endl;
cout << "1<<" << exponent << " = " << (1 << exponent) << "\t\t" << numTobinary(1 << exponent) << endl;
cout << "(runs & (1<<" << exponent << ") = " << (runs & (1 << exponent)) << "\t" << numTobinary(runs & (1 << exponent)) << endl;
// 关键代码;
if (runs & (1 << exponent)) {
str[exponent] = '1'; // 1 表示选择;
}
else {
str[exponent] = '0'; // 0 表示不选择;
}
}
return str;
}
set<string> subStringGenerator(const string& str){
set<string> ss;
int len = str.length();
int cont = 1 << len; // 子集个数 = 1 * 2 ^ N
// i 从1开始时,无 空集;默认从0开始,存在空集;
for (int i = 1; i < cont; i++) {
string binStr = binaryStringGenerator(len, i);
cout << "binStr = " << binStr << endl;
string temp;
for (int i = 0; i < (int)str.length(); ++i) {
// 所构造的二进制串出现非法元素时,引发中断;
assert('0' == binStr[i] || binStr[i] == '1');
if (binStr[i]=='1') {
temp += str[i];
}
}
ss.insert(temp);
}
return ss;
}
template<typename T>
void outRsult(const set<T>& myset) {
for (auto item : myset) {
cout << item << "\t";
}
cout << endl;
}
int main() {
string str; // 待输入的字符串;
while (cin >> str) {
auto ss = subStringGenerator(str);
//cout << ss.size() << endl;
outRsult(ss);
}
return 0;
}
样例测试与与案例分析:
单个元素
双个元素
多个元素
其他测试
代码优化:
上述代码运行效率测试:
以 所耗时间为参照标准,不进行数据输出(注释掉)、记录运行时长:
程序运行时长测试办法(两行代码)
#include<ctime>
…
clock_t startTime = clock();
… 需要测试的代码运行过程 …
cout << "总共耗时:" << double(clock() - startTime) / CLOCKS_PER_SEC << "s" << endl;
直接在main函数运行二进制模拟:
此时,既不存储、也不进行数据输出,仅仅是二进制模拟,所耗时长大大降低;
理论上,待测试的字符串长度可达64位,但一般程序设计都有运行时长要求,
若只是二十位以内的字符串长,可以考虑使用二进制模拟解决。
#include<iostream>
#include<string>
#include <ctime>
using namespace std;
// 2 ^ 64 是上限,故 只能处理母串长度 <64 的情况;
int main() {
string str; // 待输入的字符串;
while (cin >> str) {
clock_t startTime = clock();
int len = str.length();
int cont = 1 << len;
for (int i = 1; i < cont; ++i) { // i 表示即将要选择子集元素个数;
for (int j = 0; j < len; j++) {
if (i & (1 << j)) {
//cout << str[j];
}
}
//cout << " ";
}
//cout << endl;
cout << "总共耗时:" << double(clock() - startTime) / CLOCKS_PER_SEC << "s" << endl;
}
return 0;
}
二进制模拟在查找共同子序列问题上的应用:
二进制模拟串实现暴力破解——暴力枚举出(最长)公共子序列
排列问题详见笔者另外一篇博客:
转载请注明出处。
如需交流,可直接评论区留言或者发送私信。
联系方式:[email protected]
2019/11/23 22:33