寻找用于生成数据序列的替代解决方案

时间:2011-01-19 21:04:48

标签: c++ stl

我有一个问题,让我们说:

  

从前一个生成一个新字符串   一个遵循一条规则。
  1,11,21,   1211,111221,312211,13112221,......

  1. “1”:表示一个数字1,因此下一个字符串将为“11”
  2. “11”:表示两个数字1,因此下一个字符串将为“21”
  3. “21”:表示一个数字2和一个数字1,因此下一个字符串将为“1211” ....
  4. 这是我的解决方案:

    #include <string>
    #include <iostream>
    
    using namespace std;
    
    class look_n_say {
    public:
        look_n_say( int n ) : n( n ) {
        }
    
        friend ostream& operator <<( ostream& out, const look_n_say& rhs ) {
            string result;
            string init_str( "1" );
            out << init_str << endl;
            for( int i = 1; i < rhs.n; ++i ) {
                result = rhs.get_new_str( init_str );   
                out << result << '\n';
                init_str = result;
                result.clear();
            }
            return out;
        }
    
    private:
        string get_new_str( const string& str ) const {
            int cnt( 1 );
            string result;
            for( string::size_type i = 0, len = str.length(); i < len; ++i ) {
                if( i < len - 1 && str[i] == str[i + 1] ) {
                    ++cnt;
                }
                else {
                    result.append( 1, cnt + 48 );
                    result.append( 1, str[i] );
                    cnt = 1;
                }
            }
            return result;
        }
    
    private:
        int n;
    };
    
    int main() {
        look_n_say lns( 10 );
        cout << lns << endl;
        return 0;
    }        
    

    我对我的解决方案不满意的原因是我错过了使用STL算法的优雅解决方案。我想到了std::transform,但发现无法应用它。有没有更好的方法来解决这个问题?任何人都可以与我分享?任何有关我的编码风格的反馈和评论将不胜感激!请告诉我我的编码风格有多糟糕,我将从中学习。

    谢谢,

3 个答案:

答案 0 :(得分:2)

据我所知,没有可以生成此序列的STL“单行”。您可以使用算法组合来尝试描绘相邻连续值的所有范围,可能使用std::adjacent_difference,但老实说,我认为手写循环会更优雅。

在一个不相关的说明中,我不确定我是否支持你设计look_n_say的决定。在编写类时,您有一个对象,其唯一目的是将值写入ostream。您无法查询系列中的各个值,也无法更改在创建对象后获得的值的数量。每次拨打n时,您也会急切地重新计算第一个operator <<号码,这可能效率极低。我建议将班级改为:

  1. 缓存以前生成的值,以便稍后检索它们。
  2. 允许用户查询他们想要的任何外观和数字,而不仅仅是检索他们的第一个n
  3. 一种可能的设计可能是这样的:

    class LookAndSaySeries {
    public:
        string getTerm(size_t index) const; // Get the appropriate term of the series.
    
    private:
        /* Previously-retrieved values, marked mutable since getTerm() will modify even
         * though it's a semantically-const operation.
         */
        mutable vector<string> cachedValues; // Values you've handed back before.
        void generateNext() const;
    };
    
    string LookAndSaySeries::getTerm(size_t index) const {
         /* Keep generating values until you have enough to satisfy the request. */
         while (index >= cachedValues.size())
             generateNext();
    
         return cachedValues[index];
    }
    
    void LookAndSaySeries::generateNext() const {
         /* ... insert logic here to generate next term ... */
         cachedValues.push_back(/* ... that value ... */);
    }
    

    这使您可以轻松查询单个数字,而无需在每次迭代时重新计算它们。您仍然可以像以前一样将值打印到流中,但现在可以更精细地控制数字的生成方式。

答案 1 :(得分:0)

此算法中的单个步骤实际上将run-length encoding应用于先前的序列。在Rosetta Stone上有几种RLE解决方案,包括一种用于C ++的解决方案。也许这值得一瞥。

但是,该解决方案也不使用任何花哨的标准库算法。

答案 2 :(得分:0)

Fancy-pants STL方法:

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

typedef std::vector<int> T;

void thingy(const T &v, const int n)
{
    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ""));
    std::cout << std::endl;

    if (n > 0)
    {
        T w;
        for (T::const_iterator it = v.begin(); it != v.end(); )
        {
            T::const_iterator it2 = std::find_if(it, v.end(),
                                    std::bind1st(std::not_equal_to<int>(), *it));
            w.push_back(std::distance(it, it2));
            w.push_back(*it);
            it = it2;
        }

        thingy(w, n-1);
    }
}


int main()
{
    T v;
    v.push_back(1);
    thingy(v, 5);
}