LeetCode第 179 题:最大数(C++)

179. 最大数 - 力扣(LeetCode)
在这里插入图片描述

第一反应是基数排序,吗?(应该。。。)

  • 暴力解铁行不通,因为数肯定很大,得用字符串保存,也就难以进行比较
  • 肯定是要排序的,第一步排序应该是按照元素的最高位(第一位)进行排序
  • 但是第一步排序之后就不好处理了,因为元素的位数不一样(可以寻找首位相同的再进行排序,但是查找复杂度太高)
  • 既然关键在于位数不一样,那就把位数变成一样的再稳定排序就可以啦,开始!!!

怎么把位数变成一样的?

直接补 0 ?好像不行,假如输入是:

输入: [3,31,34,5,9]
输出: 9534331

正确答案是 9534331,对应的下标是:[4,3,2,0,1]

如果将输入补0对齐:

输入: [3,31,34,5,9]-->[30,31,34,50,90],按首位排序之后:[30,31,34,50,90]

逆序选择,得到的是9534313,并不正确,所以不能简单的补0

应该补的是该数的最后一位数,假设要补齐为两位,上述例子应补齐为:

补齐:[33,31,34,55,99]
排序:[31,33,34,55,99]->对应下标[1,0,2,3,4]

对应下标[1,0,2,3,4],按照这个下标在原始数组里逆序取就可以啦。

再看个例子:

输入: [3, 52, 123, 8, 67, 0, 44]
正确答案:867524431230->对应下标:[3, 4, 1, 6, 0, 2, 5]
输入补齐:[333, 520, 123, 888, 670, 000, 444]
补齐之后的排序:[000, 123, 333, 444, 520, 670, 888]
对应的逆序下标:[3, 4, 1, 6, 0, 2, 5],可见是正确的

但是,这个思路的代码在倒数第三个测试用例的时候出错了,错在对 824 和 8247这两个数的选择上:

按上面的思路,补齐后分别为8244,8247,所以先选8247后选824,得到8247824,但是实际上先选824才对(8248247)。所以不能使用最后一位补齐,这种情况应该使用第一位补齐,但是这样的话12,121这种又会错误处理。。。反正就是总有少数几个测试用例过不去。

这个思路好像进行不下去了!

不过后续还是看到了别人的基数排序,确实考虑的情况比较多:
基数排序

因为如果碰到两个数的第一位相同的时候,很难区分哪个在前哪个在后,那就采取比较吧,两种情况都考虑,看哪一个更大。

另外将数字直接转为字符串,进行比较也是可以的。

建议看官方题解的思路,传递性的证明确实不好理解,可以看这个最大数-比较规则传递性以及算法正确性的证明

class Solution {
public:
    string largestNumber(vector<int>& nums) {
        if(*max_element(nums.begin(), nums.end()) == 0) return to_string(0);
        vector<string> vec(nums.size());
        for(int i = 0; i < nums.size(); ++i)   vec[i] = to_string(nums[i]);
        sort(vec.begin(), vec.end(), [](const string &s1, const string &s2){return s1+s2 > s2+s1;});
        return accumulate(vec.begin(), vec.end(), string());
    }
};
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值