Problem

Given a list, split it into two sublists — one for the front half, and one for the back half. If the number of elements is odd, the extra element should go in the front list.

Examples

Example 1:

Input: head = [1,2,3,4,5
Output:[[1,2,3], [4,5]]

Solution

This linked list question is challenging due to the tricky edge cases that need consideration, making it more difficult than it seems to get everything right at once.

Method 1 - Get length of list

A straightforward solution involves iterating through the list twice: first to count the elements (using Find the length of the linked list) and second to find the split point.

Can we improve upon this method? Absolutely.

Method 2 - Using slow and fast pointers

We employ two pointers, lets call them slow and fast. The slow pointer moves one node at a time, while the fast pointer progresses two nodes at a time. This is very similar to Middle of the linked list Problem, but with some changes. As, we need to add the previous node to middle, for splitting up, we can handle it using such cases.

When the fast pointer reaches the end of the list, the slow pointer will be at or near the splitting point. It’s important to handle special cases. The following solution addresses all scenarios effectively. We can either use prev pointer of dummy node.

I prefer the solution with dummy node, where we insert the dummy node at the start. Then, we can point slow to dummy and fast to head. This way we can handle the edge cases.

Code

Java
Using prev Pointer
public class Solution {

	public ListNode[] splitLinkedList(ListNode head) {
		if (head == null || head.next == null) {
			return new ListNode[] {
				head, null
			}; // Handle the cases of empty list or single node list
		}

		ListNode slow = dummy;
		ListNode fast = head;
		ListNode prev = null; // To keep track of the node before the slow pointer

		// Use fast and slow pointers to find the middle
		while (fast != null && fast.next != null) {
			prev = slow;
			slow = slow.next;
			fast = fast.next.next;
		}

		// Split the list into two halves
		if (prev != null) {
			prev.next = null; // Break the link to split the list
		}

		return new ListNode[] {
			head, slow
		}; // Return the two halves
	}
}
Using dummy node
public class Solution {

	public ListNode[] splitLinkedList(ListNode head) {
		if (head == null || head.next == null) {
			return new ListNode[] {
				head, null
			}; // Handle the cases of empty list or single node list
		}

		ListNode dummy = new ListNode(0, head);
		ListNode slow = dummy;
		ListNode fast = head;

		// Use fast and slow pointers to find the middle
		while (fast != null && fast.next != null) {
			slow = slow.next;
			fast = fast.next.next;
		}
		ListNode[] ans = new ListNode[]{head, slow.next};
		slow.next = null;

		return ans;
	}
}