Pages

104 Middle of the Linked List

 Given: A singly linked list.

Goal: Return the middle node of the linked list.
If there are two middle nodes, return the second one.

Example:


Input: 1 -> 2 -> 3 -> 4 -> 5 Output: 3 Input: 1 -> 2 -> 3 -> 4 -> 5 -> 6 Output: 4


Approach: Two-Pointer (Fast and Slow Pointer) Idea: Use two pointers: Slow pointer: moves one step at a time. Fast pointer: moves two steps at a time. How It Works: When the fast pointer reaches the end of the list, the slow pointer will be at the middle. Why It Works: Fast pointer covers double the distance of slow pointer. So when fast is at the end (or past the end), slow has reached halfway.


class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def middleNode(head: ListNode) -> ListNode:
    slow = head
    fast = head

    while fast and fast.next:
        slow = slow.next        # move 1 step
        fast = fast.next.next   # move 2 steps

    return slow

103 Delete Node in a Linked List

Delete Node in a Linked List Delete

Problem Summary

You are given only a reference to a node (not the head) in a singly linked list. The node is not the tail.
You need to delete this node from the list.

What You Cannot Do

  • You cannot traverse from the head to find the previous node.

  • You do not have access to the previous node, so you can't modify its next pointer.


What You Can Do (The Trick )

You copy the value of the next node into the current node, and then delete the next node instead.

ref

class Node:
    def deleteNode(node: ListNode) -> None:
        node.val = node.next.val        # Step 1: Copy value from next node
        node.next = node.next.next      # Step 2: Skip the next node

102 Dummy references (or dummy nodes) in LinkedList

What is a dummy node?

A dummy node is a placeholder node used as the starting point of a new linked list.
It often has a value like -1 or 0, and its main purpose is not for storing data but to help simplify code logic.


Why use a dummy node?

  • To avoid handling special cases when dealing with the head of the list.

  • To build a new list easily without checking if it’s the first node.

  • To simplify pointer manipulation (especially useful in deletion or partitioning problems).

  • Prevents null pointer exceptions during iteration or insertion.


Common Scenarios / Use Cases

1. Merging Two Sorted Linked Lists

You don’t know which node will be the head of the merged list, so using a dummy node allows you to build the merged list without worrying about head initialization.

dummy = ListNode(-1)
tail = dummy

while l1 and l2:
    if l1.val < l2.val:
        tail.next = l1
        l1 = l1.next
    else:
        tail.next = l2
        l2 = l2.next
    tail = tail.next

tail.next = l1 or l2
return dummy.next

101 Linked List

 

Why Singly Linked Lists Matter

They test:

  • Understanding of pointers
  • Recursion
  • Iteration
  • Edge case handling (null nodes, head/tail issues)
  • Space and time complexity reasoning


Basic Operations on Singly Linked List

1. Insert at Head

Pseudocode:

function insertAtHead(head, value):
    newNode = Node(value)
    newNode.next = head
    return newNode  // new head

 Python Snippet:

class Node:
    def __init__(self, val):
        self.val = val
        self.next = None

def insertAtHead(head, value):
    newNode = Node(value)
    newNode.next = head
    return newNode

2. Insert at Tail

 Pseudocode:

function insertAtTail(head, value):
    newNode = Node(value)
    if head is null:
        return newNode
    temp = head
    while temp.next != null:
        temp = temp.next
    temp.next = newNode
    return head

 Python Snippet:

def insertAtTail(head, value):
    newNode = Node(value)
    if not head:
        return newNode
    temp = head
    while temp.next:
        temp = temp.next
    temp.next = newNode
    return head

3. Delete from Head

 Pseudocode:

function deleteFromHead(head):
    if head is null:
        return null
    return head.next

 Python Snippet:

def deleteFromHead(head):
    if not head:
        return None
    return head.next

4. Delete from Tail

 Pseudocode:

function deleteFromTail(head):
    if head is null or head.next is null:
        return null
    temp = head
    while temp.next.next != null:
        temp = temp.next
    temp.next = null
    return head

Python Snippet:

def deleteFromTail(head):
    if not head or not head.next:
        return None
    temp = head
    while temp.next.next:
        temp = temp.next
    temp.next = None
    return head

5. Search a Value

 Pseudocode:

function search(head, target):
    temp = head
    while temp != null:
        if temp.val == target:
            return true
        temp = temp.next
    return false

 Python Snippet:

def search(head, target):
    temp = head
    while temp:
        if temp.val == target:
            return True
        temp = temp.next
    return False

6. Reverse a Linked List

 Pseudocode:

function reverseList(head):
    prev = null
    curr = head
    while curr != null:
        next = curr.next
        curr.next = prev
        prev = curr
        curr = next
    return prev  // new head

Python Snippet:

def reverseList(head):
    prev = None
    curr = head
    while curr:
        nxt = curr.next
        curr.next = prev
        prev = curr
        curr = nxt
    return prev

7. Length of Linked List

 Pseudocode:

function getLength(head):
    count = 0
    temp = head
    while temp != null:
        count += 1
        temp = temp.next
    return count

Python Snippet:

def getLength(head):
    count = 0
    temp = head
    while temp:
        count += 1
        temp = temp.next
    return count

8. Print Linked List

 Pseudocode:

function printList(head):
    temp = head
    while temp != null:
        print temp.val
        temp = temp.next

 Python Snippet:

def printList(head):
    temp = head
    while temp:
        print(temp.val, end=" -> ")
        temp = temp.next
    print("None")



Beginner-Level Singly Linked List Questions (FAANG-Friendly)

#

Problem Name

Key Concepts

Difficulty

Platform

1

Reverse a Linked List

Iteration, Pointer manipulation

Easy

LeetCode

2

Merge Two Sorted Lists

Dummy node, Two pointers

Easy

LeetCode

3

Remove Duplicates from Sorted List

Edge-case handling

Easy

LeetCode

4

Delete Node in a Linked List

In-place manipulation

Easy

LeetCode

5

Middle of the Linked List

Fast & slow pointers

Easy

LeetCode

6

Linked List Cycle

Floyd’s Cycle Detection

Easy

LeetCode

7

Palindrome Linked List

Fast/slow pointer + reverse second half

Easy-Medium

LeetCode

8

Remove Nth Node From End of List

Two pointers, edge case

Medium

LeetCode

9

Convert Binary Number in a Linked List to Integer

Math, Iteration

Easy

LeetCode

10

Intersection of Two Linked Lists

Length comparison or hashset

Easy

LeetCode

3SUM Problem

 

Here's the correct approach for 3Sum:

In the 3Sum problem, you're looking for unique triplets that sum to zero. So, once you find a triplet, you need to skip over duplicate values from both the left pointer (l) and the right pointer (r) to avoid considering the same triplet more than once.

Correct Deduplication Logic for 3Sum:


def threeSum(nums):
    nums.sort()  # Sort the array
    n = len(nums)
    res = []

    for i in range(n - 2):
        if i > 0 and nums[i] == nums[i - 1]:  # Skip duplicates for 'i'
            continue

        l, r = i + 1, n - 1
        while l < r:
            total = nums[i] + nums[l] + nums[r]
            if total < 0:
                l += 1
            elif total > 0:
                r -= 1
            else:
                res.append([nums[i], nums[l], nums[r]])

                # Skip duplicates for 'l' and 'r'
                while l < r and nums[l] == nums[l + 1]:
                    l += 1
                while l < r and nums[r] == nums[r - 1]:
                    r -= 1

                l += 1
                r -= 1

    return res

Key Deduplication Points:

  1. Skip duplicates for i:

    • Before moving the i pointer forward, check if nums[i] is equal to nums[i - 1]. This avoids considering the same starting element multiple times.
  2. Skip duplicates for l:

    • After finding a valid triplet, use while l < r and nums[l] == nums[l + 1] to skip over duplicates on the left side (to avoid reusing the same value for l).
  3. Skip duplicates for r:

    • Similarly, use while l < r and nums[r] == nums[r - 1] to skip duplicates on the right side.

Important:

  • The check while l < r and nums[l] == nums[l+1] is valid after finding a valid triplet and moving l or r. It's there to ensure that you don't pick the same number twice for l and r.

    Without it, you might end up including the same triplet multiple times (e.g., if nums[l] == nums[l+1], the triplet formed with both values would be identical).

Example Walkthrough:

For an input like:

nums = [-1, 0, 1, 2, -1, -4]
  • After sorting: [-4, -1, -1, 0, 1, 2]
  • You would start by selecting i = -4 and try to find pairs that sum to 4 (to make a total of 0).
  • After finding a valid triplet (like [-1, 0, 1]), you'd use the deduplication logic to skip duplicate values of l and r, ensuring that each triplet is unique.

Conclusion:

Yes, while l < r and nums[l] == nums[l+1] can be used in 3Sum, but only after finding a valid triplet and ensuring no duplicate triplets are added to the result. The right logic here is to carefully avoid revisiting the same values when adjusting the l and r pointers.

Let me know if you'd like a detailed step-by-step example of how the function works for a specific input!




Remove Nth Node from End of List – LeetCode #19

Use two pointers to remove the Nth node from the end of the linked list in one pass.

Remove Nth Node from End of List

 






Naive Approach (Two Passes)

   Idea:

  1. First pass: Count the total number of nodes in the list (length).

  2. Second pass: Traverse again and stop at the (length - n)th node (just before the one to be deleted).

  3. Update the next pointer to skip the target node.


   Pseudocode: Naive Approach