Introduction to the Lesson

Today's lesson will build upon our foundational understanding of linked lists by diving into practical implementation exercises using Ruby. These problems will sharpen your coding skills and prepare you for scenarios you might encounter in technical interviews.

Problem 1: Reverse Linked List Traversal

Picture a scenario in which you have a sequence of events stored in a linked list. Your task is to look back in time — essentially, to reverse the chronology of these events. In technical terms, this means traversing a singly linked list in reverse order while keeping its structure intact. This skill is critical, whether for reversing transaction logs or simply navigating through a playlist from end to start.

Problem 1: Problem Actualization

Consider a browser's back-button functionality, where the most recently visited pages must be revisited in reverse order. This operation mirrors our task of reverse traversal in a linked list, capturing the essence of a real-world application.

Problem 1: Naive Approach

One may consider creating a new linked list while iterating over the original list, inserting each element at the head of the new list. Although this approach might work, it is an overcomplicated approach that results in extra processing and memory usage that we can avoid.

Problem 1: Efficient Approach Explanation

A more sophisticated solution would use a Ruby array to simulate a stack. Using an array, we ensure an orderly collection of the nodes' values as we navigate the list. Once the traversal is complete, we extract the values in reverse order using the array's pop method, which simulates a stack's Last-In-First-Out property.

Let's visualize it with a deck of cards: We pick each card from the top (the head of the linked list) and place it into a pile (our array). When we finish, we pick up the cards from the pile now in reverse order.

Problem 1: Solution Building

Let's tackle it with Ruby:

Ruby
1class ListNode 2 attr_accessor :value, :next 3 4 def initialize(value = 0, _next = nil) 5 @value = value 6 @next = _next 7 end 8end 9 10def reverse_print_linked_list(head) 11 # Instantiate an array to simulate a stack. 12 stack = [] 13 14 # Traverse the linked list and push node values to the array. 15 current_node = head 16 while current_node 17 stack.push(current_node.value) 18 current_node = current_node.next 19 end 20 21 # Pop from the stack to obtain elements in reversed order. 22 while !stack.empty? 23 puts stack.pop 24 end 25end

In this code, we create an array stack to store integers. We then iterate through the linked list using a while loop. For each node visited, we push its value onto the stack. After traversing the entire list, we pop the values off the stack. This reversal is possible because arrays in Ruby can act like stacks due to their Last In, First Out behavior.

Problem 2: Calculate Linked List Length

Next up, we face a seemingly simple task: determining the size of a linked list. Imagine it as a conga line at a party. You'd like to know how many people are in the line without disturbing the dance. Start at the beginning and count each person until you reach the end.

Problem 2: Problem Actualization

In scenarios such as buffering data streams or executing batch operations, we often need to know the size of a list of tasks to allocate resources efficiently. This real-world implication highlights the utility of accurately determining the length of a linked list.

Problem 2: Naive Approach

While it may be tempting to convert the linked list to an array and examine its size, such an approach is needlessly burdensome. We would create a new data structure when a more straightforward method can be employed.

Problem 2: Efficient Approach Explanation

To calculate the length efficiently, we'll employ a classic traversal technique. It's a counting exercise: start at the first node (like the first person in the conga line) and increment a counter as we follow the links until we reach the end. The counter then reflects the conga line's length.

Problem 2: Solution Building

Implementing this strategy in Ruby is straightforward:

Ruby
1def get_length(head) 2 # Initialize a counter for the length. 3 length = 0 4 5 # Iterate through the list, incrementing the length counter. 6 current_node = head 7 while current_node 8 length += 1 9 current_node = current_node.next 10 end 11 12 # Return the final count. 13 length 14end

In this code, we initialize an integer length to zero, which will serve as our counter. We then loop through each node of the linked list, incrementing length by one each time a new node is encountered. When the end of the list is reached (which we know occurs when current_node is nil), we exit the loop and return the total count.

Lesson Summary

Today, we practiced critical operations on linked lists, namely reversing a list's traversal and calculating its length. Both solutions involved traversing the linked list but with different goals in mind. We efficiently solved these problems using structurally simple yet powerful techniques in Ruby. We will transition to a series of exercises designed to reinforce your understanding of linked lists and prepare you for tackling similar problems in real-world scenarios or technical interviews.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal