|
| 1 | +from functools import cmp_to_key |
| 2 | +from typing import List |
| 3 | + |
| 4 | + |
| 5 | +class Solution: |
| 6 | + # Time Complexity: O(nlgn) |
| 7 | + # Space Complexity: O(n) for sorted(...) returns a new list. |
| 8 | + def largestNumber(self, nums: List[int]) -> str: |
| 9 | + # Degenerate Case: all 0s in nums |
| 10 | + # Executes in O(n) time, O(1) space. |
| 11 | + all_zeros = True |
| 12 | + for num in nums: |
| 13 | + if num != 0: |
| 14 | + all_zeros = False |
| 15 | + break |
| 16 | + |
| 17 | + if all_zeros is True: |
| 18 | + return "0" |
| 19 | + |
| 20 | + def compare(x: str, y: str): |
| 21 | + if (y + x) > (x + y): |
| 22 | + return 1 |
| 23 | + elif (x + y) > (y + x): |
| 24 | + return -1 |
| 25 | + else: |
| 26 | + return 0 |
| 27 | + |
| 28 | + return "".join(sorted(map(str, nums), key=cmp_to_key(compare))) |
| 29 | + |
| 30 | + |
| 31 | +class OfficialSolution: |
| 32 | + def largestNumber(self, nums: List[int]) -> str: |
| 33 | + """ |
| 34 | + Approach 1: Sorting vis Custom Comparator |
| 35 | + == Intuition == |
| 36 | + To construct the largest number, we want to ensure that the most significant |
| 37 | + digits are occupied by the largest digits. |
| 38 | +
|
| 39 | + == Algorithm == |
| 40 | + First, we convert each integer to a string. Then, we sort the array of strings. |
| 41 | + While it might be tempting to simply sort the numbers in descending order, this |
| 42 | + causes problems for sets of numbers with the same leading digit. For example, |
| 43 | + sorting the problem example in descending order would produce the number |
| 44 | + 9534303, while the correct answer can be achieved by transposing the 3 and 30. |
| 45 | + Therefore, for each pairwise comparison during the sort, we compare the numbers |
| 46 | + achieved by concatenating the pair in both orders. We can prove that this sorts |
| 47 | + into the proper order as follows: |
| 48 | + We want to prove that this pairwise comparison leads to overall correct order. |
| 49 | + Suppose not. Suppose we have an incorrect ordering. |
| 50 | + Assume that (without loss of generality), for some pair of integers a and b, our |
| 51 | + comparator dictates that a should precede b in sorted order. This means that |
| 52 | + a+b > b+a (where + represents concatenation). For the sort to produce an |
| 53 | + incorrect ordering, there must be some c for which b precedes c and c precedes |
| 54 | + a. This is a contradiction because a+b > b+a and b+c > c+b implies a+c > c+a. |
| 55 | + In other words, our custom comparator preserves transitivity, so the sort is |
| 56 | + correct. |
| 57 | + (The above lines are hand wavy. Check out |
| 58 | + https://leetcode.com/problems/largest-number/discuss/291988/ |
| 59 | + A-Proof-of-the-Concatenation-Comparator's-Transtivity |
| 60 | + for a rigorous proof) |
| 61 | + Once the array is sorted, the most "significant" number will be at the front. |
| 62 | + There is a minor edge case that comes up when the array consists of only zeroes, |
| 63 | + so if the most significant number is 0, we can simply return 0. Otherwise, we |
| 64 | + build a string out of the sorted array and return it. |
| 65 | +
|
| 66 | + == Complexity Analysis == |
| 67 | + - Time Complexity: O(nlgn) |
| 68 | + Although we are doing extra work in our comparator, it is only by a constant |
| 69 | + factor. Therefore, the overall run time is dominated by the complexity of |
| 70 | + srt, which is O(nlgn) in Python. |
| 71 | +
|
| 72 | + - Space Complexity: O(n) |
| 73 | + Here, we allocate O(n) additional space to store the copy of nums. Although |
| 74 | + we could do that work in place (if we decide that it is okay to modify |
| 75 | + nums), we must allocate O(n) space for the final return string. Therfore, |
| 76 | + the overall memory footprint is linear in the length of nums. |
| 77 | + """ |
| 78 | + largest_num = "".join(sorted(map(str, nums), key=LargerNumKey)) |
| 79 | + return "0" if largest_num[0] == "0" else largest_num |
| 80 | + |
| 81 | + |
| 82 | +class LargerNumKey(str): |
| 83 | + def __lt__(x, y): |
| 84 | + return x + y > y + x |
0 commit comments