Skip to content

Commit 0fce668

Browse files
committed
solve Largest Number
1 parent ecd74b1 commit 0fce668

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-0
lines changed

problems/largest_number.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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

tests/test_largest_number.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import unittest
2+
3+
from largest_number import Solution, OfficialSolution
4+
5+
6+
class TestLargestNumber(unittest.TestCase):
7+
def test_example_1(self):
8+
assert Solution().largestNumber(nums=[10, 2]) == "210"
9+
assert OfficialSolution().largestNumber(nums=[10, 2]) == "210"
10+
11+
def test_example_2(self):
12+
assert Solution().largestNumber(nums=[3, 30, 34, 5, 9]) == "9534330"
13+
assert OfficialSolution().largestNumber(nums=[3, 30, 34, 5, 9]) == "9534330"
14+
15+
def test_example_3(self):
16+
assert Solution().largestNumber(nums=[0, 0]) == "0"
17+
assert OfficialSolution().largestNumber(nums=[0, 0]) == "0"

0 commit comments

Comments
 (0)