LeetCode第179题_最大数

LeetCode 第179题:最大数

题目描述

给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。

注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。

难度

中等

题目链接

点击在LeetCode中查看题目

示例

示例 1:

输入: nums = [10,2]
输出: "210"

示例 2:

输入: nums = [3,30,34,5,9]
输出: "9534330"

提示

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 10^9

解题思路

方法:自定义排序

要得到最大的整数,我们需要将所有数字按照特定顺序排列。普通的排序(如按照数字大小排序)是不够的,因为我们需要考虑的是数字拼接后的大小。

关键点:

  1. 对于两个数字 a 和 b,如果将它们拼接起来,应该比较 a+b 和 b+a 这两种拼接方式哪个更大
  2. 根据这个比较规则对数组进行排序
  3. 处理特殊情况,如数组中有多个 0

实现步骤:

  1. 将数字转换为字符串
  2. 使用自定义比较函数,对于任意两个字符串 a 和 b,比较 a+b 和 b+a 的字典序
  3. 按照比较函数对字符串数组进行排序
  4. 将排序后的字符串数组连接起来
  5. 处理前导零的特殊情况,如果结果以 0 开头且长度大于 1,说明整个数组都是 0,应返回 “0”

时间复杂度:O(n log n),其中 n 是 nums 的长度(排序的时间复杂度)
空间复杂度:O(n),用于存储字符串数组

代码实现

C# 实现

public class Solution {
    public string LargestNumber(int[] nums) {
        // 将整数转换为字符串
        string[] numStrs = new string[nums.Length];
        for (int i = 0; i < nums.Length; i++) {
            numStrs[i] = nums[i].ToString();
        }
        
        // 自定义排序,比较 a+b 和 b+a 的大小
        Array.Sort(numStrs, (a, b) => (b + a).CompareTo(a + b));
        
        // 特殊情况:如果排序后的第一个数是 0,说明所有数都是 0
        if (numStrs[0] == "0") {
            return "0";
        }
        
        // 连接所有字符串
        return string.Join("", numStrs);
    }
}

Python 实现

class Solution:
    def largestNumber(self, nums: List[int]) -> str:
        # 自定义比较函数
        def compare(x, y):
            # 比较 x+y 和 y+x 的大小
            return int(y + x) - int(x + y)
        
        # 将整数转换为字符串
        nums = [str(num) for num in nums]
        
        # 根据自定义比较函数排序
        nums.sort(key=functools.cmp_to_key(compare))
        
        # 处理特殊情况:如果排序后的第一个数是 0,说明所有数都是 0
        if nums[0] == "0":
            return "0"
        
        # 连接所有字符串
        return "".join(nums)

C++ 实现

class Solution {
public:
    string largestNumber(vector<int>& nums) {
        // 将整数转换为字符串
        vector<string> numStrs;
        for (int num : nums) {
            numStrs.push_back(to_string(num));
        }
        
        // 自定义排序,比较 a+b 和 b+a 的大小
        sort(numStrs.begin(), numStrs.end(), [](const string& a, const string& b) {
            return a + b > b + a;
        });
        
        // 特殊情况:如果排序后的第一个数是 0,说明所有数都是 0
        if (numStrs[0] == "0") {
            return "0";
        }
        
        // 连接所有字符串
        string result;
        for (const string& numStr : numStrs) {
            result += numStr;
        }
        
        return result;
    }
};

性能分析

各语言实现的性能对比:

实现语言执行用时内存消耗特点
C#100 ms39.9 MB使用内置 Array.Sort 和 CompareTo 方法
Python40 ms16.1 MB使用 functools.cmp_to_key 实现自定义排序
C++4 ms11.1 MB使用 lambda 表达式实现自定义排序,性能最佳

补充说明

代码亮点

  1. 自定义排序比较函数,直接比较两个数字拼接后的大小
  2. 对特殊情况(如全是 0 的数组)进行了处理
  3. 在各个语言中都使用了内置的排序函数,保证了 O(n log n) 的时间复杂度

为什么自定义排序函数能得到正确结果?

对于任意两个数字 a 和 b,我们希望确定它们在最终结果中的相对顺序。有两种可能的排列:a 在前面(即 ab)或 b 在前面(即 ba)。我们需要选择使得结果最大的那种排列。因此,我们直接比较 ab 和 ba 的大小。

这种比较方法是有传递性的:如果 a 应该排在 b 前面,且 b 应该排在 c 前面,那么 a 一定应该排在 c 前面。这确保了我们的排序结果是正确的。

常见错误

  1. 直接对数字大小进行排序,而不是比较拼接后的结果(例如,3 和 30,直接比较会将 30 排在 3 前面,但正确的顺序应该是 3 在前面)
  2. 忘记处理特殊情况,如全 0 数组
  3. 在 Python 中使用 sorted() 函数时没有正确使用 functools.cmp_to_key

相关题目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值