【问题标题】:Array : Largest possible number数组:可能的最大数
【发布时间】:2011-06-25 06:32:45
【问题描述】:

给定一个元素数组,找出最大可能的数 通过使用数组的元素形成。
例如:10 9
答:910
2 3 5 78
答案:78532
100 9
答:9100

我知道这个问题有一个使用自定义字符串比较器的解决方案,但我不明白它是如何工作的。

    #include <iostream>
    #include <string>
    #include <algorithm>
    #include <vector>

    using namespace std;


    bool compare ( string a, string b )  
    {  
            return atoi( (a+b).c_str() ) < atoi((b+a).c_str() );  
    }

    int main()  
    {  
            vector<string> vs;  
            string s;  
            while ( cin >> s ) {  
                    vs.push_back(s);  
            }  
            sort( vs.begin(), vs.end(), compare );  
            for ( int i = vs.size()-1; i >= 0; i-- ) {  
                    cout << vs[i];  
            }  
    }   

谁能提出一个算法来解决这个问题? 将理解上述比较器的解释。 谢谢

【问题讨论】:

  • 糟糕的解决方案:nlog(n) 复杂度(排序)加上慢 compare() 函数
  • @Gene Bushuyev:有更好的复杂性解决方案吗?
  • 我之前问过这个问题,请查看我的个人资料。有一个很好的答案。
  • 它不是重复的......当我发布问题时,您无法在搜索中找到它

标签: c++ arrays algorithm


【解决方案1】:

确实,如果我们有两个字符串 ST,我们通常会按照字典顺序将它们串联起来,以使最大的数字出现。但是,当这些字符串之一是另一个字符串的前缀时,这种方法并不完美。
T = SA,即ST的前缀。我们有两种连接选择:SSASAS。显然,我们的选择将取决于哪个数字更大:ASSA。 以下是满足此算法的代码修改:

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>

using namespace std;


bool compare ( string a, string b )  
{  
        int i, j;
        for( i = 0; i < a.size() && i < b.size(); ++i )
               if( a[ i ] != b[ i ] )
                     break;
        if( i < a.size() && i < b.size() ) //  if digit mismatch happened
               return a[ i ] < b[ i ];
        if( i == a.size() )                // a is a prefix for b
        {
               string suffix = b.substr( i );
               return a + suffix < suffix + a;
        }
        else                               // b is a prefix for a
        {
               string suffix = a.substr( i );
               return suffix + b < b + suffix;
        }
}

int main()  
{  
        vector<string> vs;  
        string s;  
        while ( cin >> s ) {  
                vs.push_back(s);  
        }  
        sort( vs.begin(), vs.end(), compare );  
        for ( int i = vs.size()-1; i >= 0; i-- ) {  
                cout << vs[i];  
        }  
}

【讨论】:

  • 非常干净的解决方案!
【解决方案2】:

如果a+b 组合在b+a 之前或之后,比较器会比较两个字符串。因此,例如它说对于输入a=4; b=3,字符串"34" 小于"43",因此4 应该在3 之前。

因此,数字2 3 5 78 将被排序为78 5 3 2,因此结果为78532

【讨论】:

    【解决方案3】:

    只需通过从左到右比较数字将它们按字典顺序排序。这样较大的数字首先出现,从而使连接的数字更大。

    编辑:正如 Grigor 指出的那样,您必须首先反转字符串,将它们排序为反向 lex 顺序,然后连接并反转结果。

    【讨论】:

    • 其实这并不完全正确,因为它在某些情况下不起作用,例如:"9""91""9" 按字典顺序较小,我们将其连接为"991" . 但是"1""19""1" 按字典顺序较小,但在这种情况下,我们需要以相反的顺序使用它们:"191" 大于 "119"
    【解决方案4】:

    您正在使用比较器运算符来查找通过以两种可能的方式连接两个数字(字符串)a+bb+a 形成的两个可能数字中较大的一个。由于您有兴趣比较数字的大小,atoi() 函数用于将字符串转换为相应的数字。
    但不需要此转换。作为两个字符串的长度a+bb+a 是一样的,字典比较和数字的大小一样好。仅当比较的两个字符串的长度不相等时才需要转换。

    【讨论】:

      【解决方案5】:

      给定一个整数数组,您可以简单地对最大数执行多次二进制搜索。每次执行此操作时,将数字连接到字符串的末尾(结果),并记住排除之前添加的数字。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-08-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-22
        • 1970-01-01
        • 1970-01-01
        • 2014-12-26
        相关资源
        最近更新 更多