Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
448: Solving Linked List Problems
Linked lists are where a lot of developers first start feeling the "pointer anxiety." Since Python handles memory for us, we don't deal with raw memory addresses, but the logic of manipulating references is exactly the same. The most common mistake I see—and one I made plenty of times early on—is "breaking the chain" before you've secured the next link.
Take a look at this attempt to reverse a singly linked list. It looks logically sound at a glance, but it has a catastrophic flaw.
class Node:
def __init__(self, value):
self.value = value
self.next = None
def reverse_list(head):
prev = None
current = head
while current:
# The mistake is right here
current.next = prev
prev = current
current = current.next
return prev
The Infinite Loop of Nothingness
If you run this, you'll notice it doesn't actually reverse the list; it just destroys it. The moment we hit current.next = prev, we've severed the connection to the rest of the list. We've told the current node to point backward, which is what we want, but we've forgotten that current.next was our only map to the next node in the sequence.
When the code reaches current = current.next, it isn't moving forward to the next node in the original list. Instead, it's moving back to prev. You've essentially created a tiny loop between two nodes and lost the rest of your data to the garbage collector. This is the "classic" linked list bug: modifying a reference before you've saved the destination.
Saving the Bridge Before Burning It
To fix this, we need a temporary variable to hold the reference to the next node before we overwrite it. I like to think of it as pinning the next node to the table so it doesn't slide away while I'm rearranging the current one.
def reverse_list(head):
prev = None
current = head
while current:
# 1. Save the next node (The Bridge)
next_node = current.next
# 2. Reverse the pointer
current.next = prev
# 3. Move the window forward
prev = current
current = next_node
return prev
Now, the sequence is safe. We save current.next into next_node, then we flip the pointer. When we finally move current forward, we use that saved reference. It's a simple addition, but it's the difference between a working algorithm and a memory leak.
Dealing with the Edge Case Void
When you're solving these problems, you have to get into the habit of imagining the "empty" or "singular" states. What happens if head is None? What if there's only one node?
- Empty List: In my fixed code,
currentstarts asNone, thewhileloop never executes, and it returnsprev(which isNone). That's correct. - Single Node:
next_nodebecomesNone,current.nextbecomesNone,prevbecomes the node, andcurrentbecomesNone. It returns the single node. Also correct.
I always recommend sketching this out on paper or a whiteboard first. If you can't draw the arrows moving, you're probably going to write a bug that's a nightmare to debug in the console.
📋 Practical Task
Exercise: Deleting the N-th Node from the End of a Singly Linked List
Your task is to implement a function remove_nth_from_end(head, n). Given the head of a linked list and an integer n, remove the n-th node from the end of the list and return the head.
Requirements:
- The list is guaranteed to be long enough that
nis valid. - You should try to solve this in one single pass through the list.
- Hint: Consider using two pointers (a "fast" pointer and a "slow" pointer) spaced
nnodes apart. When the fast pointer hits the end, the slow pointer will be exactly where you need it to be.
class Node:
def __init__(self, value):
self.value = value
self.next = None
def remove_nth_from_end(head, n):
# Your code here
passThere are no comments for now.