码迷,mamicode.com
首页 > 其他好文 > 详细

【编程题目】把数组排成最小的数

时间:2014-08-18 21:51:03      阅读:444      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   os   io   for   ar   

68.把数组排成最小的数(数组、算法)。
题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个。
例如输入数组{32, 321},则输出这两个能排成的最小数字 32132。
请给出解决问题的算法,并证明该算法。

 

思路:首先,肯定要考虑溢出问题。开始想用字符串,后来改为了用list。思路是先把第一个数字放入list,然后依次把后面的数字插入到合适的位置。

关键问题就是如何判断两个数字哪一个在前面。

①对于 353 、412这样的情况,肯定是第一个数字小的在前面

②遇到数字相同的就比较下一个数字

③那像 3、 32 这样的情况,两个数字前面相同后面不一样长的  把长的数字去掉相同的部分再跟短的数字比 

如 3 、3332

3、332

3、32

3、2 后面的数字放前面

再如 321321321、321

321321、321

321、321 相等 哪个放在前面都一样

 

为了获取数字的每一位方便,有定义了一个结构,存放每个数字各个位上的数,以及位数的大小。整体代码如下:

/*
68.把数组排成最小的数(数组、算法)。
题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个。
例如输入数组{32,   321},则输出这两个能排成的最小数字 32132。
请给出解决问题的算法,并证明该算法。
start to code = 18:42
end time = 19:47
*/

#include <iostream>
#include <list>
using namespace std;

typedef struct SeperateNum
{
    int num[30]; //在前面的是低位
    int len;
}SeperateNum;

SeperateNum getSeperateNum(int n)
{
    SeperateNum s;
    s.len = 0;
    int t = n;
    while(t != 0)
    {
        s.num[s.len++] = t % 10;
        t = t / 10;
    }
    if (s.len == 0) //只有一个数字0的情况
    {
        s.num[0] = 0;
        s.len = 1;
    }
    return s;
}

bool isBefore(SeperateNum a, int na, SeperateNum b, int nb) //a 是否应该放在 b前面 n为当前判断第几个数字
{
    if (b.len - nb < 0 && a.len - na < 0) //两个数字相等 或者一个数字是另一个数字复制了 n遍 321 321321321哪个放前面都一样
    {
        return true;
    }
    else if (b.len - nb < 0 && a.len - na >= 0) //b数字比较短 且b与a的前面都相等
    {
        return isBefore(a, na, b, 1);
    }
    else if(b.len - nb >= 0 && a.len - na < 0) //a数字比较短
    {
        return isBefore(a, 1, b, nb);
    }

    if (a.num[a.len - na] > b.num[b.len - nb])
    {
        return false;
    }
    else if (a.num[a.len - na] < b.num[b.len - nb])
    {
        return true;
    }
    else //本位数字相等判断下一位
    {
        return isBefore(a, na + 1, b, nb + 1);
    }
}

void getMinNum(int * in, int len) //输入数组 和 长度
{
    list<SeperateNum> lminNum;
    list<SeperateNum>::iterator it;
    SeperateNum temp = getSeperateNum(in[0]);
    bool isInsert = false;

    lminNum.push_back(temp);
    for (int i = 1; i < len; i++)
    {
        isInsert = false;
        temp = getSeperateNum(in[i]);
        for(it = lminNum.begin(); it != lminNum.end(); it++)
        {
            if (isBefore(temp, 1, *it, 1)) //需要插入
            {
                lminNum.insert(it, temp);
                isInsert = true; 
                break;
            }    
        }
        if (isInsert == false) //没有在中间插入 插在最后面
        {
            lminNum.push_back(temp);
        }
    }
    
    cout << "组合成的最小数字是:";
    for(it = lminNum.begin(); it != lminNum.end(); it++) //输出最小的数字 注意判断结束要用 ‘ != ’ 不能用‘ < ’
    {
        for(int i = it->len - 1; i >= 0; i--)
        {
            cout<< it->num[i];
        }
    }
    cout<< endl;
}

int main()
{
    int a[5] = {321, 321321325, 3, 32};
    getMinNum(a, 4);

    return 0;
}

查到了一个讲C++不错的网址http://www.cplusplus.com/reference/list/list/insert/

整整写了100多行,用到了自定义结构、STL、递归各种复杂的东西。用了1个多小时,还不包括思考的时间。

 

在网上找答案,发现人家的答案都好简洁啊。

http://blog.csdn.net/cxllyg/article/details/7659525 经验证这里的答案正确 里面还附有证明

方法相当的简单,我怎么就没有想到。 就是把两个数a、b 正反都拼一下 ab、ba 比较一下那个数小就行了。

代码里面直接用了strcmp来做这个。

#include <iostream>
#include <string.h>
using namespace std;

const int g_MaxNumberLength=10;
char* g_StrCombine1=new char[g_MaxNumberLength*2+1];
char* g_StrCombine2=new char[g_MaxNumberLength*2+1];

int compare(const void* strNumber1, const void* strNumber2)
{
    strcpy(g_StrCombine1, *(const char**)strNumber1);
    strcat(g_StrCombine1, *(const char**)strNumber2);

    strcpy(g_StrCombine2, *(const char**)strNumber2);
    strcat(g_StrCombine2, *(const char**)strNumber1);

    return strcmp(g_StrCombine1, g_StrCombine2);
}

void PrintMinNumber(int *numbers, int length)
{
    if(numbers==NULL || length<=0)
        return;

    char** strNumbers=(char**)(new int[length]);
    for(int i=0; i<length; i++)
    {
        strNumbers[i]=new char[g_MaxNumberLength+1];
        sprintf(strNumbers[i], "%d", numbers[i]);
    }

    qsort(strNumbers, length, sizeof(char*), compare);

    for(int i=0; i<length; i++)
        cout<<strNumbers[i];
    cout<<endl;

    for(int i=0; i<length; i++)
        delete[] strNumbers[i];

    delete[] strNumbers;

}

void main()
{
    int Num;
    cin>>Num;
    int *numbers=new int[Num];
    for(int i=0; i<Num; i++)
        cin>>numbers[i];

    PrintMinNumber(numbers, Num);
    getchar();
}

 

另一个实现:

#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
using namespace std;

bool compare(const string& str1, const string &str2)
{
    string s1=str1+str2;
    string s2=str2+str1;
    return s1<s2;
}

void ComArrayMin(int *pArray, int num)
{
    int i;
    string *pStrArray=new string[num];

    for(i=0; i<num; i++)
    {
        stringstream stream;
        stream<<pArray[i];
        stream>>pStrArray[i];        
    }

    sort(pStrArray, pStrArray+num, compare);

    for(i=0; i<num; i++)
        cout<<pStrArray[i];

    cout<<endl;

    delete[] pStrArray;

}

void main()
{
    int Num;
    cin>>Num;
    int *pArray=new int[Num];

    for(int i=0; i<Num; i++)
        cin>>pArray[i];

    ComArrayMin(pArray, Num);

}

 

【编程题目】把数组排成最小的数,布布扣,bubuko.com

【编程题目】把数组排成最小的数

标签:style   blog   http   color   os   io   for   ar   

原文地址:http://www.cnblogs.com/dplearning/p/3920354.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!