# Why so many Leetcode solutions are terrible

As the 2019 recruiting season is in full swing, I’ve found myself spending a lot of time on Leetcode to keep my algorithms and data structures knowledge sharp, like many of my peers. Unfortunately though, I see so many examples of solutions that, in my opinion, really miss the point of what good code is. In this post, I’m going to look at the relatively simple Add Two Numbers problem to illustrate my point.

# The Problem

“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.”

This problem is one of the simpler ones on Leetcode, but that actually suits this blog post quite well since a harder problem would detract from the main take-aways of the post. To make sure we’re all on the same page, consider this graphic that Leetcode provides under the **Solution** tab:

In an interview setting, if the interviewee can reach this understanding of the problem posed, the solution is actually relatively straight-forward. The three-step process is basically:

(1) Decode the linked-list representations into integers.

(2) Add the integers.

(3) Encode the sum into the linked-list representation and return it.

So, I implemented my solution and then I took a look at the **Discussion** tab to compare my own solution with others’ (don’t worry, we’ll look at my solution a bit farther down).

# Discussion solutions

The most popular Python 3 answer that I came across reads as follows:

01 # Definition for singly-linked list. 02 # class ListNode: 03 # def __init__(self, x): 04 # self.val = x 05 # self.next = None 06 07 class Solution: 08 # @return a ListNode 09 def addTwoNumbers(self, l1, l2): 10 carry = 0 11 root = n = ListNode(0) 12 while l1 or l2 or carry: 13 v1 = v2 = 0 14 if l1: 15 v1 = l1.val 16 l1 = l1.next 17 if l2: 18 v2 = l2.val 19 l2 = l2.next 20 carry, val = divmod(v1+v2+carry, 10) 21 n.next = ListNode(val) 22 n = n.next 23 return root.next

This solution, by the way, is titled “Clear python code, straight forward.” Now, this blog post is not about shaming Leetcode contributors, so I do want to point out that I think this solution is really cool (it is impressive how it solves the solution with a single pass over both of the given lists). The solution, however, is neither clear nor straight-forward, because it is largely unreadable. I should mention too, that this is not a one-off in the discussions page but that this theme is present throughout Leetcode. For the curious reader, see C++ solution, easy to understand (spoiler alert: it is not particularly easy to understand), and here is the discussion tab of the problem. Even the solution provided by Leetcode is completely void of comments and use the same anti-modular design.

Anyway, in order to get back to the problem, let’s decode the solution a little:

01 # Definition for singly-linked list. 02 # class ListNode: 03 # def __init__(self, x): 04 # self.val = x 05 # self.next = None 06 07 class Solution: 08 # @return a ListNode 09 def addTwoNumbers(self, l1, l2): 10 11 carry = 0 12 root = n = ListNode(0) 13 14 # Iterate forward so long as at least one given list is still going and carry is non-zero 15 while l1 != None or l2 != None or carry != 0: 16 17 # Let's grab the values (and iterate forward) of each node that is non None 18 v1 = v2 = 0 19 if l1: 20 v1 = l1.val 21 l1 = l1.next 22 if l2: 23 v2 = l2.val 24 l2 = l2.next 25 26 # Sum the values of each node with the carry 27 sum = v1 + v2 + carry 28 29 # Get the new carry and the value to store in the node of the sum list 30 # (dividing by 10 reduces the value to a single digit) 31 # (and gets a carry for the next iteration/digit) 32 carry, val = divmod(sum, 10) 33 34 # Store value and iterate forward 35 n.next = ListNode(val) 36 n = n.next 37 return root.next

Hopefully, my comments have illuminated the solution enough that it is understandable. Even with this, however, the solution is still hard to read. Questions that I had to consider for quite a while include: How exactly is the result list created and iterated (lines 12, 35-36)? How is the while loop terminated (line 15)? What is happening on line 32? Why is it happening?

Beyond legibility, there is a much bigger problem with the code: modularity. In an interview setting, follow-up questions are not uncommon. Consider the amount of work required to accommodate the following new criteria:

(1) What if the given linked lists were instead provided with the digits in the correct order?

(2) What if an arbitrary number of numbers were given instead of just two?

(3) What if instead of adding the numbers, you had to subtract one number from the other?

I’m definitely not claiming that the code couldn’t be adjusted to deal with any of these new critera (or, even harder, a combination of (1) and (2) or of (1) and (3)). It would, however, be tedious and prone to lots of errors. Let’s take a look at the solution I provided, also in Python 3.

01 # Definition for singly-linked list. 02 # class ListNode: 03 # def __init__(self, x): 04 # self.val = x 05 # self.next = None 06 from collections import deque 07 08 class Solution: 09 # Takes ListNode integer representation and returns an integer 10 def decodeNumber(node: ListNode) -> int: 11 d = deque() 12 13 # For each digit, append on the left of the deque to build the number 14 # (appening on left to account for digits arriving in reverse order) 15 while node != None: 16 d.appendleft(str(node.val)) 17 node = node.next 18 19 # Join deque into integer and return 20 num = ''.join(list(d)) 21 return int(num) 22 23 # Takes an integer and returns a ListNode integer representation 24 def encodeNumber(num: int) -> ListNode: 25 26 # Let's build a deque from the given integer 27 d = deque(str(num)) 28 29 # Deepest value is the most significant digit 30 node = ListNode(int(d.popleft())) 31 32 # As long as there are digits, add them (from left) as a new node 33 while len(d) > 0: 34 newNode = ListNode(int(d.popleft())) 35 newNode.next = node 36 node = newNode 37 38 return node 39 40 def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: 41 42 # Decode the two given numbers for a resulting integer 43 resultNum = Solution.decodeNumber(l1) + Solution.decodeNumber(l2) 44 45 # Encode the resulting integer to the given format 46 return Solution.encodeNumber(resultNum)

The first thing you’ll notice is how I defined two new functions: **encodeNumber** and **decodeNumber**, where the bulk of the work is taking place. In terms of legibility, the immediate benefit is that reading the main function takes no more than a minute. Additionally, to anyone familiar with queues and linked lists, the en- and decoding functions are also very legible since their purposes are narrow and well-defined (no confusing divmod’s in the middle of the linked list operations).

In terms of configurability, consider the follow-up questions posed earlier:

(1) What if the given linked lists were instead provided with the digits in the correct order?

Replace each instance of **popleft** and **appendleft** with their analogues **pop** and **append**, respectively. This simply flips the order of the digits in the queue. This, by the way, is what I did for Add Two Numbers II on Leetcode, solving it in less than a minute.

(2) What if an arbitrary number of numbers were given instead of just two?

Simply call **decodeNumber** for each given number and return the encoded sum.

(3) What if instead of adding the numbers, you had to subtract one number from the other?

Simply replace the plus operator in the main function with the minus operator.

As you can hopefully see, the difference that taking a couple of minutes to think about how I could separate the different aspects of my code made a huge difference.

Seeing solutions like the example I brought up can be really dissuading (it definitely makes me feel stupid when I don’t understand a short snippet of a language I am supposedly familiar with). I hope I have gotten my point across though, that code legibility lands more-so on the shoulders of the author than the reader. So, keep that and modularity in mind as you keep practicing on Leetcode and best of luck with the 2019 recruiting season!

**Disclaimer:** I am not a recruiter. I am not an algorithms and data structures expert. I do not hold an advanced degree in Computer Science. Hell, I’m not even a software engineer; I do security and spend comparatively little time programming. These are just my personal observations and I am sure there are those who disagree. Your mileage may vary.

**Recruiters: **If you have an exciting information security internship that you think I might be right for, please contact me.