《算法之美》のn个数连接得到最小的多位整数

题目:设有n个正整数,将它们连接成一排,组成一个最小的多位整数?

例如:n=2时,2个整数32321连接成的最小整数是:32132

         n=4时,4个整数553131233连接成的最小整数为:312313355

 

解答:由于题目涉及到整数的连接,如果直接进行整数的连接,可能会超出整数的表示范围,因此我们将之转换为字符串之间的连接更简单些,同时自定义字符串的比较规则:如果字符串A+B > B+A,那么A>B。同时可以证明A+B>=B+AB+C>=C+B,则A+C>=C+A

因此,解题思路为:1)先将输入的n个整数转换成字符串;2)按照自定义的字符串比较规则将n个字符串排序;3)最后按照从小到大的顺序输出字符串,即实现连接成最小的整数。

 

代码如下:

#include <iostream>

#include <set>

#include <string>

 

class ASCENum

{

public:

    ASCENum(const char* ch) : str(ch){}

   

    //重载'<'操作符

    bool operator <(const ASCENum &other) const

    {

        if(str == other.str) 

        {

            return false;      

        }

        //下面就是我们的自定义字符串比较规则额

        std::string right = str + other.str;

        std::string left = other.str + str;

        if(right >= left) //相等时算是false

            return false;

        else if(right < left)

            return true;

    }     

   

    const char* GetStr() const

    {

        return str.c_str();     

    }

 

private:

    std::string str; 

};

 

void ASCEOut(int *target, int len)

{

    std::set<ASCENum> asceStrings;

    ASCENum temp("");

    char c[20];

    //将数据由小到大顺序插入set

    for(int i=0; i<len; i++)

    {

        itoa(target[i], c, 10); //int转为char[]

        temp = ASCENum(c);

        asceStrings.insert(temp);       

    }

    //按顺序输出,就可以实现组成一个最小的多位数

    //如果反向输出则是一个最大的多位数

    for(std::set<ASCENum>::iterator it = asceStrings.begin(); it != asceStrings.end(); it++)

    {

        std::cout<<(*it).GetStr();                               

    }

    std::cout<<std::endl;

}

 

int main()

{

    int testcase1[] = {443, 4432, 44324};

    int testcase2[] = {123, 132, 213, 231, 321, 312};

   

    ASCEOut(testcase1, 3);

    ASCEOut(testcase2, 6);

   

    system("pause");

    return 0;   

}

 

 

 参考文献:

http://zhedahht.blog.163.com/blog/static/25411174200952174133707/

http://blog.csdn.net/yysdsyl/archive/2009/06/06/4248537.aspx

要设计一个算法,使得从一个n位数中删除s位后剩下的数尽可能小,可以采用贪心算法的思想。具体步骤如下: 1. 将原始的n位数转换为字符串表示形式,这样可以方便地访问每一位数字。 2. 从左至右遍历这个字符串,维护一个大小为s+1的临时列表(或字符串)来存储将要删除的s位数字。这个临时列表用于存储可能比当前数字小的前导数字。 3. 在遍历过程中,对于每个数字,如果它比临时列表中的最后一个数字小,则将这个数字加入到临时列表中,并且如果临时列表的长度超过了s+1,则移除最后一个数字(即维持临时列表的大小为s+1)。这样,临时列表中的数字始终是当前看到的最小的s个数字。 4. 遍历结束后,临时列表中的数字就是需要删除的s位数字。 5. 构造最终的结果,将原数中不属于临时列表的数字保留下来,按原顺序连接起来,就得到了删除s位后最小的数。 下面是用Python实现的代码示例: ```python def removeKdigits(num, k): # 将数字转换为字符串 num_str = str(num) # 初始化一个栈用于存放最终结果的数字字符 stack = [] # 从左至右遍历数字字符串 for digit in num_str: # 当栈不为空且k大于0且栈顶元素大于当前遍历的数字时 while k > 0 and stack and stack[-1] > digit: # 弹出栈顶元素 stack.pop() # k减1,表示删除了一个数字 k -= 1 # 将当前数字加入栈中 stack.append(digit) # 如果栈中的数字个数多于num_str长度-k,说明还剩下未删除的数字 if len(stack) > len(num_str) - k: stack = stack[:-k] # 将栈中的数字字符连接成字符串,并去除前导零 return ''.join(stack).lstrip('0') or '0' # 示例 num = 1432219 s = 3 print(removeKdigits(num, s)) ``` 该算法的时间复杂度为O(n),空间复杂度为O(n),其中n是原始数字的位数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值