我正在练习Koeing加速C ++,并希望验证我的答案。由于网上没有可用的解决方案,我想在此发布并请专家查看我的解决方案。我不确定人们是否会希望我在这里发布。如果没有,请告诉我,我将来也不会这样做。另外,它不是功课,纯粹是我希望将我的C ++技能提升到新的水平。
问题:编写一个程序来查找字典中的所有回文。接下来,找到最长的回文。
到目前为止我做了什么 - >我已定义了测试回文的功能,也将所有单词存储在列表中。我在下面发布了我的代码。
我被困的地方我需要建议,我是否选择使用列表数据结构而不是向量?其次,我被困在如何显示最长的单词。我可以显示最长但不是最长的单词。
我在下面的尝试
bool palindromeTest( const std::string& input )
{
typedef std::string::size_type strSize;
strSize i = 0;
strSize j = input.size() - 1 ;
while( i < input.size() )
{
if ( input[i] != input[j])
{
return false;
}
i++;
j--;
}
return true;
}
int main()
{
// stores all words in a list or vector
std::list< string> listDict;
std::string readWord;
std::ifstream readFile( "/Users/apple/palidndrome-ch5-10/dict.txt" );
if( ! readFile )
{
std::cout <<" failed to open file" << std::endl;
return 0;
}
while( readFile >> readWord )
{
listDict.push_back( readWord );
}
std::string::size_type maxLen = 0 ;
std::string longestWord = " "; // to store longest palindrome
// print all the palindrome words and also which is longest palindrome.
for( std::list<std::string>::const_iterator it = listDict.begin(); it != listDict.end(); ++it )
{
if( palindromeTest( *it ) )
{
std::cout <<" the word -> " << *it << " is palindrome" << std::endl;
// find max len of palindrome;
maxLen = max( maxLen, it->size() );
longestWord = *it ;// need to change code here ?? no idea how
}
}
std::cout <<" the maximum len is = " << maxLen << std::endl;
std::cout << " the word with maximum length is " << longestWord ; // something is wrong here
return 0;
}
答案 0 :(得分:1)
矢量和列表在这里同样有效,尽管矢量效率更高。
您可以通过更改
找到最长的字词maxLen = max( maxLen, it->size() );
longestWord = *it ;// need to change code here ?? no idea how
到
if (it->size() >= longestWord.size()) {longestWord = *it;}
(你实际上不需要跟踪maxlen,因为你可以调用longestWord.size()。)
答案 1 :(得分:1)
首先进行回文试验。您正在检查字符串中的每个字符两次,这是不需要的。虽然在这种特殊情况下它并不重要,因为它只是将特定操作的时间加倍,对于某些类似的操作,它将改变语义(考虑reverse
- 在概念上非常类似于回文测试)。要改进检查,您可以使用从0
到input.size()/2
的循环计数器,也可以使用两个指针/迭代器并运行直到它们在中间相遇。另请注意,迭代到input.size()/2
将留下一个从未测试过具有奇数大小的字符串的字符,但这很好。
当需要顺序容器时,您应始终默认为std::vector<>
,而不是std::list<>
。要手动查找最大值,您应该将调用更改为max
,以检查此元素是否大于先前的最大值,然后更新max的值和字符串的位置(或字符串本身) )。在这种特殊情况下,如果重复次数很多,您还可以考虑不使用顺序容器,而是使用关联容器(std::set<std::string>
)来避免重复。但最好不要将这些单词完全存储在内存中。
您应该学会使用迭代器和标准库中的迭代器标头。例如,读取循环可以转换为:
std::vector<std::string> words;
std::copy( std::istream_iterator<std::string>( readFile ),
std::istream_iterator<std::string>(),
std::back_inserter( words );
对回文的检查可以是对std::equal
算法的调用:
bool isPalindrome( std::string const & str ) {
return std::equal( str.begin(), str.begin()+str.size()/2,
str.rbegin() );
}
通过提供适当的函子,也可以使用算法找到最长的回文:
std :: vector :: const_iterator max = std :: max_element(words.begin(),words.end(), [](std :: string const&amp; lhs,std :: string const&amp; rhs){ return lhs.size()&lt; rhs.size(); });
(使用C ++ 11中的lambdas,在C ++ 03中,您需要创建一个执行相同比较的仿函数,这需要更多的样板代码,但不应该复杂得多)
正如Antimony所指出的那样,如果你只需要这个结果,你就不需要将所有的单词保留在内存中,在这种情况下,你可以只读取每个单词,如果是最长的则只存储它回到目前为止的回文。使用标准算法并不容易实现,只需滚动自己的循环就可以了。
虽然出于学习目的,您可能想要阅读本书(针对C ++ 03),但C ++ 11中的简单解决方案可能是:
std::string longestPalindrome( std::istream& stream ) {
std::string longest;
std::for_each( std::istream_iterator<std::string>(stream),
std::istream_iterator<std::string>(),
[&longest]( std::string const & word ) {
// if is longest palindrome so far
if (std::equal( word.begin(),
word.begin()+word.size()/2,
word.rbegin()
&& word.size() > longest.size()))
{
longest = word;
}
});
return longest;
}
int main() {
std::ifstream readFile( "/Users/apple/palidndrome-ch5-10/dict.txt" );
if ( !readFile ) {
std::cerr << "failed to open file\n"; // [*]
exit(1);
}
std::string longest = longestPalindrome( readFile );
std::cout << "The longest palindrome is: '" << longest << "'\n";
}
[*]:注意,除非你真的需要,否则输出“\ n”比std::endl
更好。两者之间的区别在于std::endl
也将刷新流(强制写入),这将无意地影响性能。至于何时需要 flush ,基本上当你需要确保输出 now 时,例如在查询用户时:
std::cout << "Enter a number: " << std::flush; // Ensure that the user gets the message
// before we lock waiting for an answer:
std::cin >> number;
即使在这种情况下,更清楚(如果你需要一个换行符)转储“\ n”和std::flush
而不是std::endl
(不清楚冲洗是故意的,因为有太多的代码无休止地使用std::endl
......