I have some imminent interviews and want to sharpen my game before going into them. I'm running through some practice problems. This LeetCode challenge is to add two numbers represented as linked lists.
If you can critique this solution quite harshly, as though you would in a full-fledged SWE interview, I'd greatly appreciate it. I'm particularly concerned about memory usage and variable names.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
final_l = None
curr_l = None
remainder = 0
while l1 or l2:
digit = 0
if l1:
digit += l1.val
l1 = l1.next
if l2:
digit += l2.val
l2 = l2.next
if remainder != 0:
digit += remainder
remainder = digit // 10
digit = digit % 10
if final_l is None:
final_l = ListNode(digit)
curr_l = final_l
else:
curr_l.next = ListNode(digit)
curr_l = curr_l.next
if remainder > 0:
curr_l.next = ListNode(remainder)
return final_l
1 Answer 1
A bit of scaffolding
In order to test/review your code, I had to write a bit of additional code. In case it can be relevant to you or other reviewers, here it is:
# Definition for singly-linked list.
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def __eq__(self, other):
ret = other is not None and self.val == other.val and self.next == other.next
# print(self, other, ret)
return ret
@classmethod
def from_list(cls, l):
ret = ln = cls(l.pop(0))
while l:
e = l.pop(0)
ln.next = cls(e)
ln = ln.next
return ret
def to_list(self):
l = [self.val]
return l if self.next is None else l + self.next.to_list()
class Solution:
...
@staticmethod
def ListNodeFromInt(n):
return ListNode.from_list([int(d) for d in reversed(str(n))])
@staticmethod
def testAddTwoNumbersUsingNumbers(n1, n2):
l1 = Solution.ListNodeFromInt(n1)
l2 = Solution.ListNodeFromInt(n2)
expected_add = Solution.ListNodeFromInt(n1 + n2)
add = Solution().addTwoNumbers(l1, l2)
print(n1, n2, n1 + n2, expected_add.to_list(), add.to_list())
assert expected_add == add
@staticmethod
def unitTests():
# Edge cases
Solution.testAddTwoNumbersUsingNumbers(0, 0)
Solution.testAddTwoNumbersUsingNumbers(342, 0)
Solution.testAddTwoNumbersUsingNumbers(0, 342)
# Same length
Solution.testAddTwoNumbersUsingNumbers(342, 465)
# Different length
Solution.testAddTwoNumbersUsingNumbers(342, 46)
# Return longer than input
Solution.testAddTwoNumbersUsingNumbers(999, 999)
Solution.unitTests()
This is pretty poorly organised but it is quick and dirty. Now starts the actual review
Overall review
Your code looks good. The API is a bit awkward but it is a limitation from the programming challenge platform.
A few details can be improved anyway.
Remove non-required checks
Instead of:
if remainder != 0:
digit += remainder
You can write:
digit += remainder
Use builtins
The builtin divmod
is not the most famous but it is convenient for a pretty usual task: compute both the quotient and the remainder.
Instead of:
remainder = digit // 10
digit = digit % 10
You can write:
remainder, digit = divmod(digit, 10)
Different strategy
Instead of having a function to perform all the steps in one go, you could split the problem: define a function computing the sum of the 2 list as an integer and a function to convert that number into a list. Adding values bigger than 9 may be what we are trying to avoid though...
Explore related questions
See similar questions with these tags.