LeetCode: 179. 最大数

给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。

示例 1:

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

输入: [10,2]
输出: 210
示例 2:

示例 2:

输入: [3,30,34,5,9]
输出: 9534330
说明: 输出结果可能非常大,所以你需要返回一个字符串而不是整数。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/largest-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

看到题目第一眼想到的贪心算法,直接将int转化为string后按字串排序,然后从大到小将字符串拼接起来。写完代码、提交,,,还是太年轻了。
仔细分析后,发现问题出在两个字符串长度不同但具有相同前缀时使用默认的字串比较方式会导致错误的结果,原因在于:若长字串的后缀大于共同前缀,则长字串的比较结果因该大于短字串;若长字串的后缀小于共同前缀,则长字符串的比较结果应该小于短字符串,考虑到后缀与前缀可能又有共同的前缀且长度不同,需要递归进行比较。

解法一: 贪心法

  • 算法
  1. 将整数数据转化为string数组
  2. 排序string数组,比较方法如下:
    记比较的字串为s1与s2:
    • 若字符串不具有共同前缀,返回逐字符比较结果
    • 若s1长度大于s2长度,返回s1后缀与s2的递归比较结果
    • 若s2长度大于s1长度,返回s2后缀与s1的递归比较结果
    • 若s1与s2等长度,返回true or false
  3. 按从大到小顺序拼接字串
  • 代码
class Solution {
public:
    string largestNumber(vector<int>& nums) {
        vector<string> strs;
        string ans;
        
        for(int i=0; i<nums.size(); i++){
            strs.push_back(to_string(nums[i]));
        }
        sort(strs.begin(), strs.end(), comp);
        for(int i=strs.size()-1; i>=0; i--){
            ans+=strs[i];
        }
        int p=0;
        while(p+1<ans.size() && ans[p]=='0') p++;
        ans.erase(ans.begin(), ans.begin()+p);
        return ans;
    }
    
    static bool comp(const string &s1, const string &s2){
        int p1=0, p2=0;
        for(; p1<s1.size() && p2<s2.size(); p1++, p2++){
            if(s1[p1]<s2[p2])
                return true;
            if(s1[p1]>s2[p2]) 
                return false;
        }
        if(p1!=s1.size() && s1[p1]>=s1[0]){
            return comp(s1.substr(p1),s2);
        }
        else if(p2!=s2.size() && s2[p2]>=s2[0]){
            return comp(s1, s2.substr(p2));
        }
        else
            return s1.size()>s2.size();
    }
};
  • 时空分析
  1. 时间复杂度:记字串平均长度为k,int转string,复杂度O(kn);排序字符串,复杂度为O(knlogn);拼接字符串,复杂度O(n)。复杂度为O(nlogn)。

  2. 空间复杂度:使用string数组,O(n)

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄