我受到启发,编写了一个小型的C ++ 11程序,可以生成所谓的Conway数字,或者“外观和说”数字。基本上,给定第n个术语,例如11112,接下来只是前一个词的发音;在我们的案例4112中,因为有4个1并且只有一个2.另一个例子:'13'到'1113'。
以下是程序的完整性源代码(如果没有使用MS Visual Studio进行编译,则省略stdafx.h包含):
#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <numeric>
#include <string>
#include <vector>
using namespace std;
void print_usage(){
cout << endl << "Conway Number Generator";
cout << endl << "Arguments: initializer followed by nth term to be printed" << endl;
}
string say(string s){
// Returns string said phonetically
// e.g. '111' becomes '31'
unsigned int sz = s.size();
if (sz == 1){
s.insert(0, "1");
}
else{
s.insert(0, to_string(sz));
s.erase(2, sz-1);
}
return s;
}
string get_next(string x){
// Returns next term in Conway sequence
unsigned prev_point = 0;
vector<string> grp;
string tmp;
tmp.resize(x.size());
// Organize sequence in group of identical consecutive characters
for (unsigned int i = 0; i < x.size(); ++i){
if (i != x.size() - 1){
if (x.at(i) != x.at(i + 1)){
tmp.assign(x, prev_point, i - prev_point);
grp.push_back(tmp);
prev_point = i + 1;
tmp.clear();
}
}
else if (i != 0){
if (x.at(i) != x.at(i - 1)){
tmp = x.at(i);
grp.push_back(tmp);
tmp.clear();
}
}
}
// Phonetically say each group
// Could use a lambda: transform(begin(grp), end(grp), begin(said_grp)[=](string s){return say(s);});
// if I create a new vector<string> said_grp to copy in
// That didn't help the runtime error
for (auto& i : grp)
i = say(i);
// Join each vector<string> entry into a single string
string next_seq;
next_seq = accumulate(begin(grp), end(grp), string(""));
return next_seq;
}
string conway(string init, int n){
// Print out nth Conway term
// starting sequence at init
for (int i = 1; i <= n; ++i)
init = get_next(init);
return init;
}
int main(int argc, const char* argv[]){
if (argc < 3){
print_usage();
return 0;
}
cout << endl << "Conway number: " << conway(argv[1], stoi(argv[2])) << endl;
return 0;
}
一般方法:
n
选择计算该序列的第n个术语。conway(...)
循环执行get_next()
到初始字符串n
次。say()
'发出'数字。get_next()
通过将整个数字拆分为连续的相同数字来起作用;然后通过say()
转换每个。我遇到的问题是std::out_of_range
函数的return语句中的错误say()
。但是,我可以回想一下单独使用各种输入测试say()
,并且它从未引起异常。我必须以某种方式错误地使用它。正如我在代码注释中注意到的那样,我尝试使用STL转换而不是带有lambda的for
循环,同样的错误。
注意:对于对Conway序列感兴趣的人,请参阅Conway的原始论文。他们承认了一些有趣的属性,并且它们似乎产生了一个被称为康威常数的常数,它被证明是代数的。
答案 0 :(得分:2)
正如我在评论中提到的,这是使用调试器解决的完美问题。 80多个(非常聪明)的人看过你的代码,没有人能够通过观察完全解决它(虽然@hlt得到了很多)。经过一些调试后,我想我已经完成了其余的工作。让我们来看看这些作品。
就像hlt所说的那样,auto&
中基于范围的循环需要get_next()
,否则你永远不会真正改变grp
并继续获得原始数字。有关详细信息,请参阅this question。
另外,多亏了hlt,你有一条关于零长度字符串输入的缺失逻辑。但是,get_next()
函数中还有一个缺失的部分。以输入./conway 111 2
为例。数字111
实际上永远不会被放入grp
,因为所有字符都相同,因此if (x.at(i) != x.at(i + 1))
和if (x.at(i) != x.at(i - 1))
都不会评估为真;因此,你会得到一个空字符串作为结果。缺少的部分包含在下面。
for (unsigned int i = 0; i < x.size(); ++i){
if (i != x.size() - 1){
if (x.at(i) != x.at(i + 1)){
tmp.assign(x, prev_point, i+1 - prev_point);
grp.push_back(tmp);
prev_point = i + 1;
tmp.clear();
}
}
else if (i != 0){
if (x.at(i) != x.at(i - 1)){
tmp = x.at(i);
grp.push_back(tmp);
tmp.clear();
}
else
{
tmp.assign(x, prev_point, i+1 - prev_point);
grp.push_back(tmp);
tmp.clear();
}
}
我在上面的评论中提到的最后一个问题,并包含在此处的代码中。要将正确长度的子字符串分配到tmp
,您需要i+1-prev_point
而不是i-prev_point
。
我说开始我认为我已经抓住了其余的错误,但这可能不是真的。我建议用大量具有不同特征的数字(例如,1,12121212,0000,1222,2221等)编写一些测试及其预期结果。如果它们中的任何一个产生了意想不到的结果,那么就该回到调试器了。
答案 1 :(得分:0)
我查看了您的源代码,并注意到您的函数get_next()可以简化。我已将其替换为以下版本:
string get_next(const string & inStr) {
string result;
int len = inStr.size();
int count = 0;
// Loop over non-duplicates
for (int i = 0; i < len; i += count) {
// Calculate total number of duplicates for inStr[i]:
for (count = 0; i+count < len; count++) {
if (inStr[i+count] != inStr[i]) {
break;
}
}
// Append count + non-duplicate (count and say)
result += to_string(count) + inStr[i];
}
return result;
}
当我以“1”作为初始字符串并且5作为n运行新代码时,我得到以下输出结果:
康威号码:312211
这是正确的:1 - &gt; 11 - &gt; 21 - &gt; 1211 - &gt; 111221 - &gt; 312211
无需调试。希望这会有所帮助。