[oj.leetcode] #179 - LargestNumber, 如何在7ms内跑完 221个测试用例

来源:互联网 发布:单片机地址总线 编辑:程序博客网 时间:2024/05/21 22:33

题目:已知一个整型数组,如何排列使得最后组成一个最大整数,输出这个整数的字符串,假设都是非负。

比如[3, 30, 34, 5, 9], 结果应该是 9534330

这里选用C++。

第一感觉应该是跟排序相关,稳妥方案是快速排序quick sort. 每两个数之间比较时,应从最高位开始,一位一位进行比较,将某一位更大的数排在前面。当然需要考虑当一个数是另一个数前缀时的情况,之后再说。

由于每两个数作比较时,每一位都可能参与比较,那么整型类型就显得很麻烦了,总不能一个数在每次比较时都去一位一位剥离出来。显然字符串是个好选择,比如将 123 转化成“123”, 那么我们可以在O(1)的时间内得到第i位[i]. 

慢着,多想一下,我们应该选用C风格字符串char*, 还是C++字符串string类型呢?对于[i] 操作显然没差别。问题在于之后的快速排序,因为是原地排序,所以会用到大量的交换函数,那么这里 char* 比 string 就有优势了,所以这里我选择C风格字符串char*

继续思考两个数比较的问题,对于一个是另一个前缀,比如“12“, 与 “121“, 仔细想想,这其实是个递归,直到比较结束。

“12” ? “121”

a. "12" == "12(1)"

b. "12" ? "1" => "1" == "1"

c. "2" ? "1"    =>  "2" > "1"

所以,12 应该排在121前面,我们应该得到12121。

到此为止,我们已经把问题拆解的差不多了,另外还有些边缘情况,比如数组全0,仅一个非0等等。

完整的C++代码如下:

class Solution{public:    string largestNumber(vector<int> &num){        int n = num.size();        if(n < 1)    return string();        vector<int> vec;        char* seq[n];        int lengths[n];        int L = 0;    // total length of all char*        bool allZero = true;        for(int i=0; i<n; i++){ // init char* for int element            int val = num[i];            if(val == 0){                vec.push_back(0);            }else{                allZero = false;                while(val > 0){  // save 123 in vector<> as 3,2,1                    vec.push_back(val % 10);                    val /= 10;                }            }            int l = vec.size();            char* curr = new char[l+1];            curr[l] = '\0';            for(int j=0; j < l; j++){  // save reversed vec in curr                curr[j] = '0' + vec[l-1 - j];            }            seq[i] = curr;            lengths[i] = l;            L += l;            vec.clear();        }        if(allZero){  // all zero case is special            for(int i=0; i<n; i++){                delete[] seq[i];                seq[i] = 0;            }            return string("0");        }        quick_sort(seq, n, lengths);        // generate string from seq[]        char result[L+1];        result[L] = '\0';        int t = 0;        for(int i=0; i<n; ++i){            for(int j=0; j < lengths[i]; ++j){                result[t++] = seq[i][j];            }        }        for(int i=0; i<n; i++){            delete[] seq[i];            seq[i] = 0;        }        return string(result);    }private:    int compDeciFromHigh(char* decL, int nL, char* decR, int nR){        int i=0;        while(i < nL && i < nR){            if(decL[i] != decR[i]){                return decL[i] > decR[i] ? 1 : -1;            }            i++;        }        int res = 0;        if(nL == nR)    return res;        int deltaLen = max(nL, nR) - i;  // i == min(nL, nR)        // next: compare the tail of long str and the short str        if(i == nL){  // left str is short            res = compDeciFromHigh(decL, nL, decR + nL, deltaLen);        }else{  // right str is short            res = compDeciFromHigh(decL + nR, deltaLen, decR, nR);        }        return res;    }    void quick_sort(char* seq[], int n, int* lengths){        if(n < 2)    return;        int p = 0, q = -1, t = n-1;        while(p < t){            if(compDeciFromHigh(seq[p], lengths[p],                    seq[t], lengths[t]) > 0){  // move higher decimal ahead                q++;                swap_chpp(&(seq[q]), &(seq[p]));                swap_ip(lengths + q, lengths + p);            }            p++;        }        q++;        swap_chpp(&(seq[q]), &(seq[t]));        swap_ip(lengths + q, lengths + t);        quick_sort(seq, q, lengths);        quick_sort(seq + (q+1), n-1 - q, lengths + (q+1));        return;    }    void swap_chpp(char **p, char **q){        char *tmp = *p;        *p = *q;        *q = tmp;        tmp = 0;    }    void swap_ip(int *p, int *q){        int tmp = *p;        *p = *q;        *q = tmp;    }};
代码有点长。除了开始阶段,要对每一个整型数转化得到字符串,另外我还用了一个数组来专门存放每个C风格字符串的长度,这样也好过回头用strlen() 再去量一遍每个的长度,代价就是在排序时,每次交换元素,也要对相应的长度元素作交换。

虽然看起来有点罗嗦,但事实证明一点一滴的优化都是值得的。最后这份代码实现在oj.leetcode的线上测试中,只用了7ms跑完了全部221个测试用例,这个成绩在所有提交代码中几乎也就是最好的了,有图为证:)

Ps, 对我而言,这份代码很好的诠释了C++语言相比于java/python在性能上的巨大优势。

0 0