剑指offer 面试题45. 把数组排成最小的数(中)
考查应聘者解决大数问题的能力。应聘者在面试的时候要意识到,把两个int型的整数拼接起来得到的数字可能会超出int型数字能够表达的范围,从而导致数字溢出。我们可以用字符串表示数字,这样就能简捷地解决大数问题。另外,面试官可能要求面试者将比较规则证明出来。
Question
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
示例 1: 1
2输入: [10,2]
输出: "102"1
2输入: [3,30,34,5,9]
输出: "3033459"0 < nums.length <= 100
说明:输出结果可能非常大,所以你需要返回一个字符串而不是整数。拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0。
测试用例
功能测试(输入的数组中有多个数字;输入的数组中的数字有重复的数位;输入的数组中只有一个数字)。 特殊输入测试(表示数组的指针为 nullptr
指针)。
本题考点
本题有两个难点;第一个难点是想出一种新的比较规则来排序一个数组;第二个难点是证明这个比较规则是有效的,并且证明根据这个规则排序之后,把数组中所有数字拼接起来得到的数字是最小的。要想解决这两个难点,要求应聘者有很强的数学功底和逻辑思维能力。 考查应聘者解决大数问题的能力。应聘者在面试的时候要意识到,把两个int型的整数拼接起来得到的数字可能会超出int型数字能够表达的范围,从而导致数字溢出。我们可以用字符串表示数字,这样就能简捷地解决大数问题。
Intuition
基本思想
- 此题求拼接起来的 “最小数字” ,本质上是一个排序问题。
- 排序判断规则: 设 \(x\) 和 \(y\) 为 \(nums\) 任意两数字的字符串格式,则:
- 若拼接字符串 \(x + y > y + x\),则 \(x > y\),即 \(y\) 应该放到 \(x\) 前面。例如,当 \(x=3\) 和 \(y=30\) 时,\(x + y=330\),\(y + x=303\),即 \(x + y > y + x\),则 \(x > y\),即 \(y\) 应该放到 \(x\) 前面;
- 反之,若 \(x + y < y + x\),则 \(x < y\),即 \(x\) 应该放到 \(y\) 前面。例如,当 \(x=50\) 和 \(y=80\) 时,\(x + y=5080\),\(y+x=8050\),有 \(x + y < y + x\),则 \(x < y\),即 \(x\) 应该放到 \(y\) 前面;
- 根据以上规则,套用任何排序方法对 \(nums\) 执行排序即可。
- 考虑到结果溢出的问题,一般都需要将 Int 类型数字转换成 list 类型数组,但是这道题由于不做加减法,只做 Int 类型数字的拼接,所以用 Str 类型表示 Int 类型来防止溢出就可以了。
算法流程
初始化: 字符串列表 \(strs\) ,保存各数字的字符串格式; 列表排序: 应用以上 “排序判断规则” ,对 \(strs\) 执行排序; 返回值: 拼接 \(strs\) 中的所有字符串,并返回。
复杂度分析
时间复杂度 \(O(N \log N)\) : \(N\) 为最终返回值的字符数量( \(strs\) 列表的长度 \(\leq N\));使用快排或内置函数的平均时间复杂度为 \(O(N \log N)\) ,最差为 \(O(N^2)\)。 空间复杂度 \(O(N)\) : 字符串列表 \(strs\) 占用线性大小的额外空间。
Code
- 基于内置的
sort
和functools.cmp_to_key
函数。
1 |
|
- 自定义快排
1 |
|
Python Trick
functools.cmp_to_key
将老式的比较函数(comparison function
)转化为关键字函数(key function
)。与接受 key function
的工具一同使用(如 sorted(), min(), max(), heapq.nlargest(), itertools.groupby()
)。该函数主要用来将程序转成 Python 3 格式的,因为 Python 3 中不支持比较函数。比较函数是可调用的,接受两个参数,比较这两个参数并根据他们的大小关系返回负值、零或正值中的某一个。关键字函数也是可调用的,接受一个参数,同时返回一个可以用作排序关键字的值。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!