Wow! Haven’t made a blog post in awhile, shame on me. Let’s get back to business. I’m going to start a blog series on various different data structures and how to work with them. I find this to be a useful topic for things such as programming interviews and competitive programming.
In this first section, I’ll brainstorm some practical uses for the Linked List, and go over a couple common Linked List problems from Cracking the Coding Interview v5.
Why use Linked Lists?
Good question, when I first learned them I honestly saw no reason to ever use them. Fast forward to today, and I think they’re a fundamental data structure that you will likely use in nearly every project. Stacks and Queues are special types of Linked Lists and are very common.
Some practical examples of Linked Lists:
- A deck of cards
- A list of directions
And generally, we want to use Linked Lists when:
- There are an unknown # of items
- You need the ability to re-arrange, insert, and delete in various different locations.
Linked Lists are very good at insertion and deletion, having a worst case time complexity of O(1) for both.
Next I’ll go over some common algorithms you will implement when using a Linked List.
Remove duplicates from an unsorted Linked List.
Deletion is a strength of the Linked List, so it’s important to know how to implement it. Why implement your own when most Linked List classes will include it? Well, I think it’s nice to know how and why some things work, instead of blindly using a provided method. Also, code interviews.
Anyway, it sounds pretty simple, and it is, but if you haven’t worked with Linked Lists in awhile then it’s easy to forget.
First thing’s first, if a null value is passed, then we will want to instantly return because we can’t delete something from an empty list.
Let’s discuss how we properly delete. Deletion is achieved in a Linked List by changing the next value of a node. So if we have 1->2->3, then we simply set the next value of 1 to 3, which leaves us with 1->3.
In this problem, we want to delete all the duplicates, so we will need iterate the list in two separate loops. Both loops terminate when the node pointer reaches the end of the list, which is when the next value is equal to null. The structure will look something like:
We will be using the concept of a runner. The runner is simply a pointer that moves through the Linked List at a different pace from the original pointer. The purpose of the pointer is that it allows us to freely move through the Linked List within the inner loop, while maintaining our outer loop pointer for comparisons. This is just a standard nested loop, but modified for Linked List traversal.
And honestly… that might be the hardest part. All we need to do now is apply what I wrote previously about implementing deletion.
Breaking this down:
- We use two loops to iterate the list. The first loop moves to the next node after the second loop iterates the entire list, which gives us coverage for our duplicate comparisons.
- If a duplicate is found then we set the node’s next value to the node’s next,next value, which essentially gives us deletion. Else, move to the next node in our runner pointer.
- Move the the curr pointer to the next node each time the first loop completes.
That was a nice warmup, so let’s do something a little more complex:
Given two numbers represented by two lists, write a function that returns sum list. The sum list is list representation of addition of two input numbers. The result will not be in reverse order.
First List: 5->6->3 // represents number 365
Second List: 8->4->2 // represents number 248
Resultant list: 6->1->3 // represents number 613
This is a painful problem because my intuitive solution involves a lot of conversions.
I have broken the problem down into these steps:
- Create a runner pointer that will fill the Linked List, and a head pointer which will be the value returned.
- Convert both lists to Strings.
- Reverse both Strings.
- Convert the Strings to ints, and sum them.
- Convert the resulting int back into a String.
- Store the first value of the String as an int in the head of the Linked List.
- Loop through the remainder of the String (using the runner pointer), appending the rest of the digits.
- Return head pointer.
What a royal pain… here we go. I’ll start by initializing some variables, and converting the lists to Strings. This can be achieved by iterating through the Linked Lists and storing the values.
The problem states that the values are actually in reverse order, so the next step is to reverse both strings, sum them as ints, and convert back to String. YAY conversions. I’ll use StringBuilder to do the reversing, although the manual method of using a char array would work too.
One caveat is to remember to convert the StringBuilder objects back into Strings before using parseInt(). Now that we FINALLY have our sum in a nice String format, we need to convert the digits of this String into a Linked List. I’ll accomplish this by looping through the indices of the String.
One thing worth mentioning is that before the loop starts, we need to store the first value. This is because we will be setting the next values of our Linked List, which does not cover the first value.
Phew.. that wasn’t so bad aside but it’s a bit messy with all these conversions. Do I think it’s a good solution? Well, it could definitely be better.
Thanks for reading.