179. 最大数
179. 最大数
题目链接(中等)
题目描述
给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。
注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。
数据范围:
1 <= nums.length <= 1000 <= nums[i] <= 10^9
示例
示例 1:
输入: nums = [10,2]
输出: "210"
示例 2:
输入: nums = [3,30,34,5,9]
输出: "9534330"
核心思路
要使拼接后的字符串字典序最大,需要确定一种排序规则。
对于两个数字字符串 a 和 b:
- 如果
a + b > b + a,则a应该排在b前面; - 如果
a + b < b + a,则b应该排在a前面; - 如果相等,顺序无所谓。
为什么这样排序是对的?
假设最优排列中 b 在 a 前面,但 a + b > b + a。交换 a 和 b 后,整体拼接结果会变大,与“最优”矛盾。因此最优排列必须满足 a + b >= b + a,即按上述规则排序。
全 0 的特殊情况:
如果排序后第一个字符串是 "0",说明所有数字都是 0,直接返回 "0",避免返回 "000..."。
方法:自定义排序
思路及解法
- 将所有数字转为字符串;
- 使用自定义比较器排序:
- 若
a + b > b + a,a排在前面; - 否则
b排在前面;
- 若
- 拼接排序后的字符串;
- 若结果首位为
'0',返回"0"。
Python 3 中 sort 不再支持 cmp 参数,需要用 functools.cmp_to_key 包装比较函数。
代码
from functools import cmp_to_key
class Solution:
def largestNumber(self, nums: list[int]) -> str:
# 转为字符串
strs = list(map(str, nums))
# 自定义比较器:a+b 与 b+a 比较
def compare(a: str, b: str) -> int:
if a + b > b + a:
return -1 # a 排在 b 前面
elif a + b < b + a:
return 1 # b 排在 a 前面
else:
return 0
strs.sort(key=cmp_to_key(compare))
# 拼接结果
res = ''.join(strs)
# 处理全 0 的情况
if res[0] == '0':
return "0"
return res复杂度分析
- 时间复杂度:$O(n \log n \cdot k)$,其中
n是数组长度,k是字符串平均长度。排序需要 $O(n \log n)$ 次比较,每次比较拼接字符串,代价 $O(k)$。 - 空间复杂度:$O(n \cdot k)$,存储所有字符串和排序结果。
关键细节
1. 为什么比较 a + b 和 b + a
因为最终结果是所有字符串的拼接,两个字符串的相对顺序只影响它们拼接后的局部顺序。要让整体最大,就应让局部拼接 a + b 尽可能大。
2. 排序规则的方向
Python 的 sort 默认升序,compare(a, b) 返回负数表示 a 应排在 b 前面。
a + b > b + a时,a应该在前,返回-1;a + b < b + a时,b应该在前,返回1。
3. 全 0 的处理
例如 nums = [0, 0],排序后拼接得到 "00",但正确答案是 "0"。因此需要检查结果首位是否为 '0'。
4. 不能用普通数值排序
不能直接按数值大小排序,也不能简单按字符串字典序排序。例如 "9" 和 "34",数值上 34 > 9,但拼接 "934" > "349",所以 "9" 应排在 "34" 前面。
5. 比较器的传递性
a + b > b + a 这种比较关系满足传递性,因此可以安全地作为排序规则使用。
总结
- 核心思想:自定义排序,比较
a + b和b + a; - 排序规则:
a + b > b + a时a在前; - 全 0 处理:结果首位为
'0'时返回"0"; - 时间复杂度 $O(n \log n \cdot k)$,空间复杂度 $O(n \cdot k)$;
- 通用套路:「拼接后比较大小」→ 自定义排序。
相关题目
- LC 45. 跳跃游戏 II(贪心)
- LC 56. 合并区间(排序 + 贪心)
- LC 435. 无重叠区间(排序 + 贪心)
- LC 973. 最接近原点的 K 个点(排序)
179. 最大数
https://mingsm17518.github.io/2026/10/22/刷题笔记/Leetcode/171. Excel 表列序号/