7
\$\begingroup\$

The task is taken from LeetCode. I would appreciate an assessment of whether my coding style follows good practices, and if there are any habits or patterns you would find concerning when working together on a codebase.

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Example:

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)

Output: 7 -> 0 -> 8

Explanation: 342 + 465 = 807.

My solution (Python3):

# Definition for singly-linked list provided by the platform.
class ListNode:
 def __init__(self, val=0, next=None):
 self.val = val
 self.next = next
# My solution 
# (Leetcode doesn't really let you put things in an __init__ method in a defined way 
# (we don't know if a new instance of Solution will be created for each test case), 
# so I didn't have one).
class Solution:
 def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
 self.sumHead: ListNode = ListNode(0)
 self.sumLinkedList: ListNode = self.sumHead
 self.carry: int = 0
 while l1 and l2:
 # both numbers still have digits
 # Sanity Check
 assert self.carry in [0, 1]
 self.addDigitAndProcessCarry(l1.val + l2.val + self.carry)
 
 # move to the next node for both numbers
 l1 = l1.next
 l2 = l2.next
 # move to the next node for the sum
 if l1 or l2 or self.carry:
 self.sumLinkedList.next = ListNode(0)
 self.sumLinkedList = self.sumLinkedList.next
 for linkedListNotConsumed in [l1, l2]:
 # only one linked list has more digits to be processed
 while linkedListNotConsumed:
 # Sanity Check
 assert self.carry in [0, 1]
 self.addDigitAndProcessCarry(linkedListNotConsumed.val + self.carry)
 
 # move to the next node
 linkedListNotConsumed = linkedListNotConsumed.next
 if linkedListNotConsumed or self.carry:
 self.sumLinkedList.next = ListNode(0)
 self.sumLinkedList = self.sumLinkedList.next
 
 if self.carry:
 # Sanity Check
 assert self.carry in [0, 1]
 self.sumLinkedList.val = 1
 return self.sumHead
 
 def addDigitAndProcessCarry(self, value: int) -> None:
 if value >= 10:
 self.sumLinkedList.val = value - 10
 self.carry = 1
 else:
 self.sumLinkedList.val = value
 self.carry = 0
toolic
16.9k6 gold badges30 silver badges224 bronze badges
\$\endgroup\$

2 Answers 2

6
\$\begingroup\$

Naming

The PEP 8 style guide recommends snake_case for function and variable names. I realize the LeetCode site requires you to give the primary function those names, but you would otherwise name the function as add_two_numbers.

Also, addDigitAndProcessCarry would be add_digit_and_process_carry

For variables, sumHead would be sum_head, etc.

Comments

Many of your comments are helpful. However, this comment is not needed:

# My solution 
# (Leetcode doesn't really let you put things in an __init__ method in a defined way 
# (we don't know if a new instance of Solution will be created for each test case), 
# so I didn't have one).

Again, I realize you added this to explain the LeetCode restrictions.

Documentation

PEP 8 recommends adding docstrings for functions. The docstring would decscribe what the function does and how it does it, similar to the description of the problem in the question:

def add_two_numbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
 """
 Given two non-empty linked lists representing two non-negative integers...
 """

DRY

I see this code repeated 3 times:

assert self.carry in [0, 1]

I'm not sure you need to do that check in that many places, but if you do, you could create a helper function for the check to reduce the repetition.

answered Dec 12 at 14:40
\$\endgroup\$
8
\$\begingroup\$

Within the confines of Leetcode's requirements, this is about as straightforward a solution as can be hoped for. A few style suggestions have been pointed out by toolic.

The following code can be simplified a bit:

 def addDigitAndProcessCarry(self, value: int) -> None:
 if value >= 10:
 self.sumLinkedList.val = value - 10
 self.carry = 1
 else:
 self.sumLinkedList.val = value
 self.carry = 0

If we modulo value by 10, we can assume that is the next digit, and the carry is simply value divided (ensure integer division!) by 10.

 def addDigitAndProcessCarry(self, value: int) -> None:
 self.sumLinkedList.val = value % 10
 self.carry = value // 10

If writing within the confines of Leetcode's Solution class doesn't make sense, you are free to write your own functions and classes outside of it, and then simply wrap your solution in Solution.addTwoNumbers.

LeetCode's data structures

LeetCode's linked list data structure is dumb. It doesn't do nice things like let you iterate over it using built-in functionality in Python. But you don't have to live with that restriction.

You can implement that behavior yourself!

As an example, converting to and from iterators for LeetCode's ListNode:

def list_to_iter(lst):
 while lst:
 yield lst.val
 lst = lst.next
def iter_to_list(i):
 try:
 cur = head = ListNode(next(i))
 except StopIteration:
 return
 
 try:
 while x := next(i):
 cur.next = ListNode(x)
 cur = cur.next
 except StopIteration:
 return head

Note that you might also monkey patch this behavior into ListNode.

answered Dec 12 at 14:44
\$\endgroup\$
1
  • 2
    \$\begingroup\$ You can get the quotient and remainder in a single operation using the built-in divmod() function. self.carry, self.sumLinkedList.val = divmod(value, 10) \$\endgroup\$ Commented 2 days ago

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.