[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[挑战题]Largest Number

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

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

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

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

这些数所能拼凑出的最大数字是 9 5 34 3 30
  1. // 2018-09-29
  2. # include <stdio.h>
  3. # include <stdlib.h>
  4. typedef long long i64;
  5. typedef struct { int tail; int val; } Num;
  6. void sort(int*, int*, int);
  7. int cmp(const void*, const void*);
  8. int main (){
  9.     int test[] = { 3, 30, 34, 5, 9 };
  10.     int len    = sizeof(test) / sizeof(*test);
  11.     int sorted[len];
  12.     sort (test, sorted, len);
  13.     for (int i = 0; i < len; i++)
  14.         printf ("%d ", sorted[i]);
  15.    
  16. }
  17. # define join(A, B) (A->val * (i64)B->tail + B->val)
  18. int cmp(const void* A, const void* B){
  19.     Num* a = (Num*) A;
  20.     Num* b = (Num*) B;
  21.     i64 ab = join (a, b);
  22.     i64 ba = join (b, a);
  23.     if (ab == ba) return 0;
  24.     return ab > ba ? -1 : 1;
  25. }
  26. void sort(int* test, int* sorted, int len){
  27.     Num n[len];
  28.     for (int i = 0; i < len; i++){
  29.         int tail = 1;
  30.         int val  = test[i];
  31.         while (val) tail *= 10, val /= 10;
  32.         
  33.         n[i].tail = tail;
  34.         n[i].val  = test[i];
  35.     }
  36.     qsort(n, len, sizeof(Num), cmp);
  37.     for (int i = 0; i < len; i++) sorted[i] = n[i].val;
  38. }
  39.    
复制代码
New BEE

TOP

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

TOP

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

评分人数

New BEE

TOP

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

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

评分人数

TOP

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

故题重游,C语言版:
Submission Details
221 / 221 test cases passed.
Status: Accepted
Runtime: 0 ms
  1. char outStr[];
  2. int CompNums(const void* a, const void* b){
  3. char* str1=*(char**)a;
  4. char* str2=*(char**)b;
  5. int i, L1=strlen(str1), L2=strlen(str2);
  6. for(i=0; i<10; i++){
  7. if(*str1=='\0'){str1-=L1;}
  8. if(*str2=='\0'){str2-=L2;}
  9. if(*str1 != *str2){break;}
  10. str1++, str2++;
  11. }
  12. return *str2-*str1;
  13. }
  14. char* largestNumber(int* nums, int numsSize) {
  15. int i;
  16. outStr[0]=0;
  17. char* p[numsSize];
  18. for(i=0; i<numsSize; i++){p[i]=(char*)malloc(sizeof(char)*16);sprintf(p[i], "%d\0", nums[i]);}
  19. qsort(p, numsSize, sizeof(char*), CompNums);
  20. for(i=0; i<numsSize; i++){strcat(outStr, p[i]);}
  21. return outStr[0]=='0'?"0":outStr;
  22. }
复制代码
>>>
补充,针对本帖所有回帖的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++可以做更多的事。

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

TOP

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

TOP

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

回复 3# CrLf

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

最慢时 184ms, 最快时 116ms

在 my submissions 里记录了每一次提交测试的结果
  1. /**
  2. * @param {number[]} nums
  3. * @return {string}
  4. */
  5. var largestNumber = function(nums) {
  6.    
  7. nums = nums.map(function(num) {
  8.   return '' + num;
  9. });
  10.    
  11.     var rs=[],re=[],p=0;
  12.     rs[p] = 0;
  13.     re[p++]= nums.length-1;
  14.     var ss,ee,t;
  15.     while (p) {
  16.         ss = rs[--p];
  17.         ee = re[p];
  18.         if (ss >= ee)
  19.             continue;
  20.         var mid = nums[ee];
  21.         var left = ss, right = ee - 1;
  22.         while (left < right) {
  23.             while (nums[left] + mid > mid + nums[left] && left < right)
  24.                 left++;
  25.             while (mid + nums[right] >= nums[right] + mid && left < right)
  26.                 right--;
  27.             t = nums[left];
  28.             nums[left] = nums[right];
  29.             nums[right] = t;
  30.         }
  31.         if (mid + nums[left] >= nums[left] + mid) {
  32.             t = nums[left];
  33.             nums[left] = nums[ee];
  34.             nums[ee] = t;
  35.         } else
  36.             left++;
  37.         rs[p] = ss;
  38.         re[p++] = left - 1;
  39.         rs[p] = left + 1;
  40.         re[p++] = ee;
  41.     }
  42.     if (nums[0] == 0) return '0';
  43.     return nums.join('');
  44. };
复制代码
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. 1、用结构体 struct_num 保存数字和进位,排序时用 (long long) 数值比较大小,等到输出时再转为字符串
  2. 2、分设 10 个数组 hash 表,用于保存由 0-9 开头的数字组成的数组,这样只需要对 1-9 各组单独排序即可
  3. 3、函数自实现/内联,就题解题,节省函数调用开销
复制代码

TOP

C
  1. void q_sort(char* arr[], const int len) {
  2.     typedef struct _Range {
  3.         int start, end;
  4.     } Range;
  5.     Range new_Range(int s, int e) {
  6.         Range r;
  7.         r.start = s;
  8.         r.end = e;
  9.         return r;
  10.     }
  11.     if (len <= 0)
  12.         return;
  13.     Range r[len];
  14.     int p = 0;
  15.     r[p++] = new_Range(0, len - 1);
  16.     while (p) {
  17.         Range range = r[--p];
  18.         if (range.start >= range.end)
  19.             continue;
  20.         char* mid = arr[range.end], * cp;
  21.         int left = range.start, right = range.end - 1;
  22.         while (left < right) {
  23.             while (GTR(mid, arr[left]) && left < right)
  24.                 left++;
  25.             while (!GTR(mid, arr[right]) && left < right)
  26.                 right--;
  27.             cp = arr[left], arr[left] = arr[right], arr[right] = cp;
  28.         }
  29.         if (!GTR(mid, arr[left]))
  30.             cp = arr[left], arr[left] = arr[range.end], arr[range.end] = cp;
  31.         else
  32.             left++;
  33.         r[p++] = new_Range(range.start, left - 1);
  34.         r[p++] = new_Range(left + 1, range.end);
  35.     }
  36. }
  37. int GTR(char* s1, char* s2) {
  38.     char * p1 = s1, * p2 = s2;
  39.     while (1) {
  40.         if (!*p1 && !*p2) return 1;
  41.         if (!*p1) p1 = s2;
  42.         if (!*p2) p2 = s1;
  43.         if (*p1 > *p2)
  44.             return 1;
  45.         else if (*p1 < *p2)
  46.             return 0;
  47.         else p1++, p2++;
  48.     }
  49. }
  50. char* largestNumber(int* nums, int numsSize) {
  51.     char strs [numsSize][11], * strPtrs[numsSize], * cp1, * cp2, * strRet = malloc(10 * numsSize + 1), ch;
  52.     int i, j, k, t;
  53.     for (i = 0; i < numsSize; i++) {
  54.         t = *(nums + i);
  55.         j = 0;
  56.         k = -1;
  57.         // digits convert to string
  58.         do {
  59.             strs[i][j++] = '0' + t % 10;
  60.         } while ((t /= 10) > 0);
  61.         strs[i][j] = '\0';
  62.         // reverse string
  63.         *(strPtrs + i) = cp1 = *(strs + i);
  64.         while (--j > ++k)
  65.             * (cp1 + j) ^= *(cp1 + k), * (cp1 + k) ^= *(cp1 + j), * (cp1 + j) ^= *(cp1 + k);
  66.     }
  67.     q_sort(strPtrs, numsSize);
  68.     // printf("After q_sort\n");
  69.     // for (i = numsSize - 1; i >= 0; i--) printf("%s\n", strPtrs[i]);
  70.     cp2 = strRet;
  71.     if (strPtrs[numsSize - 1][0] == '0') {
  72.         *strRet = '0';
  73.         *(strRet + 1) = '\0';
  74.         return strRet;
  75.     }
  76.     for (i = numsSize - 1; i >= 0; i--) {
  77.         cp1 = *(strPtrs + i);
  78.         while (ch = *(cp1++)) *(cp2++) = ch;
  79.     }
  80.     *cp2 = '\0';
  81.     return strRet;
  82. }
复制代码
1

评分人数

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

TOP

返回列表