Sort List Leetcode Problem 148 [Python Solution]
Sorting is a fundamental problem in computer science, and in this blog post, we will tackle the Sort List problem from LeetCode.
This problem asks us to sort a linked list in ascending order.
While sorting an array is a common task, sorting a linked list adds an extra layer of complexity.
However, we can use the popular sorting algorithm, Merge Sort, to efficiently solve this problem.
We will explore the problem overview, constraints, and edge cases that our solution must consider.
We’ll then dive into the code for both the problem solution and the supporting functions, discussing the time and space complexity along the way.
Problem Overview
Given the head of a linked list, we need to return the list after sorting it in ascending order.
Let’s take a look at a couple of examples:
Example 1:
Input: head = [4,2,1,3]
Output: [1,2,3,4]
Example 2:
Input: head = [-1,5,3,4,0]
Output: [-1,0,3,4,5]
Example 3:
Input: head = []
Output: []
Constraints
- The number of nodes in the list is in the range [0, 5 * 10^4].
- -10^5 <= Node.val <= 10^5
Now, let’s start by understanding the constraints and edge cases a valid solution must consider.
Understanding Sort List Constraints
The problem’s constraints specify that the linked list can have a varying number of nodes, ranging from 0 to 5 * 10^4. Each node’s value can be as large as -10^5 to 10^5. These constraints are essential to consider when designing our solution to ensure it performs efficiently and handles edge cases effectively.
Edge Cases a Valid Solution Must Consider
Before delving into the code, it’s crucial to consider the edge cases to ensure our solution handles all possible scenarios.
Here are the edge cases we need to account for:
- An empty linked list: When the input linked list is empty, our function should return an empty list, as there’s nothing to sort.
- A single-node linked list: If the linked list consists of just one node, it’s already sorted, and our function should return it as is.
- Linked lists with negative values: Since the constraints allow for negative values, our solution must handle them correctly during sorting.
Now, let’s proceed to the solution for the Sort List problem.
Sort List LeetCode Problem Solution
1. Bruteforce Approach
One approach to solve this problem is to use a brute-force method.
We can iterate through the linked list and, for each node, find its correct position in the sorted list and insert it.
While this approach is correct, it’s highly inefficient, with a time complexity of O(n^2)
, where n is the number of nodes.
We can do better, so let’s explore a more efficient approach.
2. Efficient Approach with Merge Sort
Merge Sort is a popular sorting algorithm known for its efficiency and stability.
In the context of this problem, it’s particularly suitable for sorting a linked list efficiently with a time complexity of O(n log n)
.
Here’s how it works:
- Base Cases: We handle the base cases first.
If the linked list is empty or contains only one node, it’s already sorted, and we return it as is.
- Splitting: We split the linked list into two halves, roughly equal in size.
To do this, we find the middle node using the “slow” and “fast” pointers technique.
The “slow” pointer moves one step at a time, while the “fast” pointer moves two steps at a time.
When the “fast” pointer reaches the end, the “slow” pointer is at the middle node.
- Recursion: We recursively sort both halves of the linked list.
This step effectively breaks down the problem into smaller subproblems.
- Merging: We merge the two sorted halves into a single sorted list.
The merge process involves comparing the values of nodes in both halves and selecting the smaller value to add to the result list.
We continue this process until both halves are merged.
- Returning the Result: Finally, we return the merged sorted list.
Let’s implement this efficient approach in Python:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def sortList(self, head: ListNode) -> ListNode:
# Base cases
if not head or not head.next:
return head
# Split the linked list into two halves
mid = self.get_mid(head)
left, right = self.sortList(head), self.sortList(mid)
# Merge the two sorted halves
return self.merge_two_sorted(left, right)
def merge_two_sorted(self, list1: ListNode, list2: ListNode) -> ListNode:
if not list1:
return list2
if not list2:
return list1
sentinel = ListNode()
prev = sentinel
while list1 and list2:
if list1.val < list2.val:
prev.next = list1
list1 = list1.next
else:
prev.next = list2
list2 = list2.next
prev = prev.next
if list1:
prev.next = list1
else:
prev.next = list2
return sentinel.next
def get_mid(self, head: ListNode) -> ListNode:
mid_prev = None
while head and head.next:
mid_prev = mid_prev.next if mid_prev else head
head = head.next.next
mid = mid_prev.next
mid_prev.next = None
return mid
This Python code implements the Merge Sort algorithm for sorting a linked list.
It handles the base cases, splits the list, recursively sorts the halves, merges the sorted halves, and returns the final sorted list.
Time and Space Complexity
Now, let’s analyze the time and space complexity of our solution.
Time Complexity: Our efficient approach using Merge Sort has a time complexity of O(n log n)
, where n is the number of nodes in the linked list.
The splitting and merging steps are both efficient, leading to this optimal time complexity.
Space Complexity: The space complexity is O(log n)
as it corresponds to the recursive call stack.
Our algorithm does not create any additional data structures that depend on the size of the input.
Reasoning Behind Our Approach
Merge Sort is a suitable choice for this problem because it efficiently handles the sorting of linked lists, even in the presence of large data sets.
The “divide and conquer” nature of Merge Sort helps us break down the problem into smaller, more manageable parts.
By splitting the linked list, sorting each half separately, and then merging them back together, we achieve a sorted list without excessive memory usage or computational effort.
Our choice to use recursive functions for splitting, sorting, and merging simplifies the problem and makes the code more readable.
By applying the “slow” and “fast” pointers technique to find the middle node, we efficiently split the list into two halves.
In summary
, our approach leverages the strengths of Merge Sort and the recursive nature of the problem to provide an optimal solution.
Related Interview Questions By Company:
Related Interview Questions By Difficulty:
Related Interview Questions By Category:
Conclusion
In this blog post, we tackled the Sort List problem from LeetCode.
We discussed the problem overview, constraints, and edge cases that a valid solution must consider.
We explored both a brute-force approach and an efficient solution using Merge Sort to sort a linked list in ascending order.
By designing an efficient algorithm, implementing it in Python, and analyzing the time and space complexity, we have provided a comprehensive guide to solving this problem.
Sorting linked lists can be challenging, but with the right approach, we can achieve optimal results.
If you found this post helpful, please consider liking and subscribing to support the our platform.
If you have any questions, suggestions, or would like to discuss this problem further, please don’t hesitate to comment.
Happy coding!
Now, it’s your turn to tackle this problem and further explore the world of sorting algorithms and linked lists.
Good luck!