myesn

myEsn2E9

hi
github

Reverse the first half of the linked list, then connect it with the second half.

This problem can be divided into two algorithmic problems: [Middle of the Linked List] and [Reverse Linked List].

Middle of the Linked List (Two Pointers)#

With the help of two pointers, fast and slow, the fast pointer moves 2 steps each round, and the slow pointer moves 1 step each round.

The number of steps taken by fast is always twice that of slow, so when the fast pointer traverses the entire linked list, the slow pointer points to the middle node of the linked list. Since a linked list with an even length has two middle nodes, two cases need to be considered:

  • Odd length of the linked list: When fast reaches the [tail node] of the linked list, slow is exactly at the [middle node].
  • Even length of the linked list: When fast reaches [null] (beyond the [tail node]), slow is exactly at the [second middle node].

Based on the above rules, we should exit the loop when fast encounters or goes beyond the tail node, and return slow.

// Linked list with odd length
ListNode oddHead = new ListNode(1, new ListNode(2, new ListNode(3, new ListNode(4, new ListNode(5, null))))));
// Linked list with even length
ListNode evenHead = new ListNode(1, new ListNode(2, new ListNode(3, new ListNode(4, new ListNode(5, new ListNode(6, null))))));

Console.WriteLine("odd head middleNode val: {0}", MiddleNode(oddHead).Val);
Console.WriteLine("even head middleNode val: {0}", MiddleNode(evenHead).Val);

// Middle of the Linked List
ListNode MiddleNode(ListNode head)
{
    // Initialize the fast and slow pointers, both pointing to the head node of the linked list
    ListNode? fast = head, slow = head;

    // Exit the loop when fast encounters or goes beyond the tail node
    while (fast != null && fast.Next != null)
    {
        fast = fast.Next.Next;
        slow = slow!.Next;
    }

    return slow!;
}

class ListNode
{
    public int Val { get; set; }
    public ListNode? Next { get; set; }
    public ListNode(int val, ListNode? next)
    {
        Val = val;
        Next = next;
    }
}

If the question requires returning the "first middle node", then we should exit the loop when fast encounters the tail node or its predecessor. In this case, modify the condition to while fast.next and fast.next.next.

Reverse Linked List#

Approach 1: Iteration (Two Pointers)#

Traverse the linked list and modify the next reference pointer when accessing each node, as shown in the code comments.
image
image
image

// Initialize the linked list
ListNode node = new ListNode(1, new ListNode(2, new ListNode(3, new ListNode(4, new ListNode(5, null))))));

ListNode reverseNode = ReverseNode(node);
while (reverseNode != null)
{
    Console.WriteLine("reverseNode val: {0}", reverseNode.Val);
    reverseNode = reverseNode.Next;
}

// Reverse Linked List: Iteration (Two Pointers)
ListNode ReverseNode(ListNode head)
{
    // Initialize pre and cur, pointing to null and the head node respectively
    ListNode pre = null, cur = head;
    while (cur != null)
    {
        ListNode tmp = cur.Next; // Temporarily store the successor node

        cur.Next = pre;          // Modify the reference pointer
        pre = cur;               // Temporarily store the current node

        cur = tmp;               // Visit the next node
    }

    return pre;
}

class ListNode
{
    public int Val { get; set; }
    public ListNode? Next { get; set; }
    public ListNode(int val, ListNode? next)
    {
        Val = val;
        Next = next;
    }
}

Final Code#

// Q: Reverse the first half of the linked list and connect it with the second half

// Initialize a linked list with odd length
using System.Diagnostics;

ListNode oddHead = new ListNode(1, new ListNode(2, new ListNode(3, new ListNode(4, new ListNode(5, null))))));
// Initialize a linked list with even length
ListNode evenHead = new ListNode(1, new ListNode(2, new ListNode(3, new ListNode(4, new ListNode(5, new ListNode(6, null))))));

// Reverse the first half of the linked list and connect it with the second half
Console.WriteLine("Linked list with odd length:");

Stopwatch sw = Stopwatch.StartNew();
ListNode? finalOddHead = ReverseLeftOfMiddleAndCombineRightOfMiddle(oddHead);
sw.Stop();
Console.WriteLine($"Time elapsed: {sw.ElapsedMilliseconds}ms");

while (finalOddHead != null)
{
    Console.WriteLine(finalOddHead.Val);
    finalOddHead = finalOddHead.Next;
}

// Reverse the first half of the linked list and connect it with the second half
Console.WriteLine("Linked list with even length:");

sw = Stopwatch.StartNew();
ListNode? finalEvenHead = ReverseLeftOfMiddleAndCombineRightOfMiddle(evenHead);
sw.Stop();
Console.WriteLine($"Time elapsed: {sw.ElapsedMilliseconds}ms");

while (finalEvenHead != null)
{
    Console.WriteLine(finalEvenHead.Val);
    finalEvenHead = finalEvenHead.Next;
}

ListNode ReverseLeftOfMiddleAndCombineRightOfMiddle(ListNode head)
{
    // Find the middle node of the linked list
    // Use two pointers, fast and slow, where the fast pointer moves 2 steps each time and the slow pointer moves 1 step each time. Exit the loop when the fast pointer encounters or goes beyond the tail node, and return the slow pointer, which represents the middle node.
    ListNode fast = head, slow = head;
    while (fast != null && fast.Next != null)
    {
        fast = fast.Next.Next;
        slow = slow.Next;
    }

    // When the length of the linked list is odd, slow is exactly the middle node
    // When the length of the linked list is even, slow is the last node of the two middle nodes
    ListNode middleNode = slow;

    // Reverse the left part of the linked list
    // Use iteration (two pointers)
    // Here, we make pre point to the middle node, so that after reversing the left part of the linked list, the last node of the left part points to the right part of the linked list (the middle node), thus connecting the reversed linked list with the right part
    ListNode pre = middleNode, cur = head;
    // The current node in the current loop is not null and is before the middle node, so only reverse the left part of the linked list
    while (cur != null && cur.Val != middleNode.Val)
    {
        // Temporarily store the successor node
        ListNode tmp = cur.Next;

        // Modify the reference pointer
        cur.Next = pre;
        // Temporarily store the current node
        pre = cur;

        // Visit the next node
        cur = tmp;
    }

    return pre;
}

// Singly linked list structure
class ListNode
{
    public int Val { get; set; }
    public ListNode? Next { get; set; }
    public ListNode(int val, ListNode? next)
    {
        Val = val;
        Next = next;
    }
}

References#

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.