返回列表 发帖

[挑战题]Largest Number

本帖最后由 523066680 于 2016-8-23 10:52 编辑

这里有一个算法竞赛网站出的题目 https://leetcode.com/problems/largest-number/

你可以选自己擅长的语言做题并上传代码,该网站会用各种极端情况的输入值测试你的代码,如果没有出错,则同其他人上传的代码效率做比较、排名

问题179. Largest Number
Given a list of non negative integers, arrange them such that they form the largest number.
For example, given [3, 30, 34, 5, 9], the largest formed number is 9534330.
Note: The result may be very large, so you need to return a string instead of an integer.
Credits:
Special thanks to @ts for adding this problem and creating all test cases.
Subscribe to see which companies asked this questionCOPY
以下是本人渣翻译
给出一系列正整数,对这些数进行排列,使其拼凑出一个尽可能大(最大)的数。
例如,给出[3, 30, 34, 5, 9],则这些数所能拼凑出的最大数字是 9534330
注:给出的数组元素数量不定,结果可能非常非常大,所以你需要将结果作为字符串返回而不是int类型的整数(尤其是对于那些强类型的语言)COPY
可惜可以在该网站上传测试的语言类型有限,C/C++, java, python, ruby, js, go
[url=][/url]

这些数所能拼凑出的最大数字是 9 5 34 3 30
// 2018-09-29
# include <stdio.h>
# include <stdlib.h>
typedef long long i64;
typedef struct { int tail; int val; } Num;
void sort(int*, int*, int);
int cmp(const void*, const void*);
int main (){
    int test[] = { 3, 30, 34, 5, 9 };
    int len    = sizeof(test) / sizeof(*test);
    int sorted[len];
    sort (test, sorted, len);
    for (int i = 0; i < len; i++)
        printf ("%d ", sorted[i]);
   
}
# define join(A, B) (A->val * (i64)B->tail + B->val)
int cmp(const void* A, const void* B){
    Num* a = (Num*) A;
    Num* b = (Num*) B;
    i64 ab = join (a, b);
    i64 ba = join (b, a);
    if (ab == ba) return 0;
    return ab > ba ? -1 : 1;
}
void sort(int* test, int* sorted, int len){
    Num n[len];
    for (int i = 0; i < len; i++){
        int tail = 1;
        int val  = test[i];
        while (val) tail *= 10, val /= 10;
        
        n[i].tail = tail;
        n[i].val  = test[i];
    }
    qsort(n, len, sizeof(Num), cmp);
    for (int i = 0; i < len; i++) sorted[i] = n[i].val;
}
    COPY
New BEE

TOP

来个python的,大概在60ms, 一个很巧的比较方法,我是想不出来 - -,参考人家的。
https://www.geeksforgeeks.org/ar ... ggest-number-set-2/
class Solution:
   
    def largestNumber(self,nums):
        l = len(str(max(nums)))+1
        new = [((str(i)*l)[:l],str(i)) for i in nums]
        new.sort(reverse = True)
        res = "".join([i[1] for i in new])
        return "0" if res[0]=="0" else resCOPY

TOP

自由主义。
#!perl
my @n = ( 3, 30, 34, 5, 9 );
print sort { $b . $a cmp $a . $b } @n;COPY
1

评分人数

New BEE

TOP

本帖最后由 CrLf 于 2016-11-16 01:36 编辑

JS 修改后耗时约为 109ms
var largestNumber = function(nums) {
    return nums
        .sort((a,b) => ''+b+a > ''+a+b ? 1 : -1)
        .join('')
        .replace(/^0+(?=.)/,'')
}COPY
尽量用 ES6 的语法来写的版本看起来也很萌...
var largestNumber = function(nums) {
    let arr = [];
    for(let a of nums)arr.unshift(`${a}`)
    let retArr = arr.sort((a,b) => b+a > a+b ? 1 : -1)
    return retArr[0]==='0' ? '0' : retArr.join('')
}COPY
1

评分人数

TOP

本帖最后由 happy886rr 于 2016-11-14 00:49 编辑

故题重游,C语言版:
Submission Details
221 / 221 test cases passed.
Status: Accepted
Runtime: 0 ms
char outStr[];
int CompNums(const void* a, const void* b){
char* str1=*(char**)a;
char* str2=*(char**)b;
int i, L1=strlen(str1), L2=strlen(str2);
for(i=0; i<10; i++){
if(*str1=='\0'){str1-=L1;}
if(*str2=='\0'){str2-=L2;}
if(*str1 != *str2){break;}
str1++, str2++;
}
return *str2-*str1;
}
char* largestNumber(int* nums, int numsSize) {
int i;
outStr[0]=0;
char* p[numsSize];
for(i=0; i<numsSize; i++){p[i]=(char*)malloc(sizeof(char)*16);sprintf(p[i], "%d\0", nums[i]);}
qsort(p, numsSize, sizeof(char*), CompNums);
for(i=0; i<numsSize; i++){strcat(outStr, p[i]);}
return outStr[0]=='0'?"0":outStr;
}COPY
>>>
补充,针对本帖所有回帖的C代码,在100万次的测试当中,只有21楼aa77dd@163.com兄的代码速度最快,100万次耗时0.7秒,本人用itoa函数也只能做到100万次耗时1.1秒。其他C语言方案均耗时数秒,并且存在严重漏洞。
>>>
另外小于5000次的测试根本无法体现性能,几乎都是0毫秒。只在百万次的测试上个别方案才会出现极大的漏洞。
2

评分人数

TOP

回复 26# 523066680


    这书扫完了。这作者的套路就是放地图炮喷或者狂奶某个语言,然后再指责别人狂热不可理喻,能在言语上无论如何都让自己站在比较优越的位置。本身就是个语言宗教粉,但是会标榜自己是自由主义。
去学去写去用才有进步。安装python3代码存为xx.py 双击运行或右键用IDLE打开按F5运行

TOP

回复 24# aa77dd@163.com


    要看稳定值,我看到120毫秒那个档很集中,绝不是偶然,一定有什么我还没想到的办法

TOP

本帖最后由 xxpinqz 于 2016-8-27 00:04 编辑

回复 26# 523066680

过谦了。
谢谢你的建议。奶瓶、尿布得花费好大精力了,实在力所不及。
学无先后,达者为师。你也不必介怀当年所耗费精力,毕竟假设的条件就是假设。
而且也说不准你这学习的精神就是你当年留下的烙印。况且能在喜欢的事情上下功夫,本身就是一种乐趣~
发现本帖跑题的都是我~~~

这书在豆瓣上评价不错,有空看看,爱看书,但都是0.1桶水。。
初学BAT,非专业。代码不适当之处还望前辈们多多指点。在此表示感谢!

TOP

本帖最后由 523066680 于 2016-8-26 23:33 编辑

回复 25# xxpinqz

个人意见:
    多学几种语言,批处理之后,推荐ruby 或者 python,最好先熟悉C语言。
然后如果要自己打造应用,C# 或者 C++

刚工作那会儿有大量时间,我很后悔在批处理特效上面花太多时间,我不是说特效没卵用,而是搞图形的话应该一开始就上C/C++,可惜,当时缺少视野。
然后花了小量时间学Python,放弃后转而投入大量业余时间学Perl,这是手感上和批处理最像的。不过我觉得时间成本不太划算,C#、C++可以做更多的事。

最后,关于语言的吐槽,推荐一本书:《程序员的呐喊》
[url=][/url]

TOP

为啥你们脑袋这么好使呢,在这论坛混了这么久,还是只会bat。
初学BAT,非专业。代码不适当之处还望前辈们多多指点。在此表示感谢!

TOP

本帖最后由 aa77dd@163.com 于 2016-8-26 20:40 编辑

回复 3# CrLf

多测试几次就能做到, 我用同一个代码提交了多次

最慢时 184ms, 最快时 116ms

在 my submissions 里记录了每一次提交测试的结果
/**
* @param {number[]} nums
* @return {string}
*/
var largestNumber = function(nums) {
   
nums = nums.map(function(num) {
  return '' + num;
});
   
    var rs=[],re=[],p=0;
    rs[p] = 0;
    re[p++]= nums.length-1;
    var ss,ee,t;
    while (p) {
        ss = rs[--p];
        ee = re[p];
        if (ss >= ee)
            continue;
        var mid = nums[ee];
        var left = ss, right = ee - 1;
        while (left < right) {
            while (nums[left] + mid > mid + nums[left] && left < right)
                left++;
            while (mid + nums[right] >= nums[right] + mid && left < right)
                right--;
            t = nums[left];
            nums[left] = nums[right];
            nums[right] = t;
        }
        if (mid + nums[left] >= nums[left] + mid) {
            t = nums[left];
            nums[left] = nums[ee];
            nums[ee] = t;
        } else
            left++;
        rs[p] = ss;
        re[p++] = left - 1;
        rs[p] = left + 1;
        re[p++] = ee;
    }
    if (nums[0] == 0) return '0';
    return nums.join('');
};COPY
1

评分人数

    • 523066680: 没错,可能和服务器占用有关PB + 6

TOP

回复 22# CrLf

没仔细看你的代码, 估计用到了这种方式

比较 830 和 8308

预处理时, 计算出了大于 各数位数 的最小的 10 的幂
830(1000), 8308(10000)

比较时:
互相乘以对方的特征幂 再加上对方, 得到等位数拼接串:

830 * 10000 + 8308 <--> 8308 * 1000 + 830

最后得到比较结果
为防止 int 类型溢出, 必须用超出 int 范围的类型处理

字符数组指针方式比较仍然烦琐
2

评分人数

TOP

本帖最后由 CrLf 于 2016-8-25 00:29 编辑

回复 19# happy886rr


    感觉排序方式不是最重要的,个人经验,结构优化的收益远比冒泡和快速排序之间的效率差异大得多:
1、用结构体 struct_num 保存数字和进位,排序时用 (long long) 数值比较大小,等到输出时再转为字符串
2、分设 10 个数组 hash 表,用于保存由 0-9 开头的数字组成的数组,这样只需要对 1-9 各组单独排序即可
3、函数自实现/内联,就题解题,节省函数调用开销COPY

TOP

C
void q_sort(char* arr[], const int len) {
    typedef struct _Range {
        int start, end;
    } Range;
    Range new_Range(int s, int e) {
        Range r;
        r.start = s;
        r.end = e;
        return r;
    }
    if (len <= 0)
        return;
    Range r[len];
    int p = 0;
    r[p++] = new_Range(0, len - 1);
    while (p) {
        Range range = r[--p];
        if (range.start >= range.end)
            continue;
        char* mid = arr[range.end], * cp;
        int left = range.start, right = range.end - 1;
        while (left < right) {
            while (GTR(mid, arr[left]) && left < right)
                left++;
            while (!GTR(mid, arr[right]) && left < right)
                right--;
            cp = arr[left], arr[left] = arr[right], arr[right] = cp;
        }
        if (!GTR(mid, arr[left]))
            cp = arr[left], arr[left] = arr[range.end], arr[range.end] = cp;
        else
            left++;
        r[p++] = new_Range(range.start, left - 1);
        r[p++] = new_Range(left + 1, range.end);
    }
}
int GTR(char* s1, char* s2) {
    char * p1 = s1, * p2 = s2;
    while (1) {
        if (!*p1 && !*p2) return 1;
        if (!*p1) p1 = s2;
        if (!*p2) p2 = s1;
        if (*p1 > *p2)
            return 1;
        else if (*p1 < *p2)
            return 0;
        else p1++, p2++;
    }
}
char* largestNumber(int* nums, int numsSize) {
    char strs [numsSize][11], * strPtrs[numsSize], * cp1, * cp2, * strRet = malloc(10 * numsSize + 1), ch;
    int i, j, k, t;
    for (i = 0; i < numsSize; i++) {
        t = *(nums + i);
        j = 0;
        k = -1;
        // digits convert to string
        do {
            strs[i][j++] = '0' + t % 10;
        } while ((t /= 10) > 0);
        strs[i][j] = '\0';
        // reverse string
        *(strPtrs + i) = cp1 = *(strs + i);
        while (--j > ++k)
            * (cp1 + j) ^= *(cp1 + k), * (cp1 + k) ^= *(cp1 + j), * (cp1 + j) ^= *(cp1 + k);
    }
    q_sort(strPtrs, numsSize);
    // printf("After q_sort\n");
    // for (i = numsSize - 1; i >= 0; i--) printf("%s\n", strPtrs[i]);
    cp2 = strRet;
    if (strPtrs[numsSize - 1][0] == '0') {
        *strRet = '0';
        *(strRet + 1) = '\0';
        return strRet;
    }
    for (i = numsSize - 1; i >= 0; i--) {
        cp1 = *(strPtrs + i);
        while (ch = *(cp1++)) *(cp2++) = ch;
    }
    *cp2 = '\0';
    return strRet;
}COPY
1

评分人数

    • 523066680: 你们的花括号都不换行吗……PB + 12

TOP

返回列表