This page collects battle-tested Java templates for every major linked-list pattern you’ll see on LeetCode. Each section includes ready-to-use code, the signal phrases that tell you which pattern to reach for, and a quick explanation of the core idea. Bookmark it, copy what you need, and focus your energy on the actual problem logic.
New to Linked Lists? A linked list is a chain of nodes where each node points to the next. Unlike arrays, you can’t jump to index i — you must walk from the head. The tradeoff: O(1) insert/delete at known positions, but O(n) access.
Quick-Reference Summary
| Pattern | Signal Phrases | Key Idea |
|—|—|—|
| Two Pointers | “middle”, “kth from end”, “intersection” | Fast moves 2x, slow moves 1x |
| Dummy Node | “delete head”, “merge”, “insert at front” | Avoids null-check edge cases |
| Reversal | “reverse list”, “reverse between” | Rewire next pointers |
| Merge | “merge sorted”, “merge k lists” | Compare heads, advance smaller |
| Cycle Detection | “has cycle”, “cycle start” | Floyd’s: fast meets slow = cycle |
When to use: Every linked-list problem — this is the building block. Know the struct by heart so you never waste time on boilerplate.
Standard Definition
Alternative Definitions
Common Construction Methods
Utility Functions
Example Usage
// Standard ListNode definition used in LeetCodeclassListNode{intval;publicListNodenext;publicListNode(){this.val=0;this.next=null;}ListNode(intx){this.val=x;this.next=null;}ListNode(intx,ListNodenext){this.val=x;this.next=next;}}
Alternative Definitions
// Without default constructorclassListNode{intval;publicListNodenext;publicListNode(intx){this.val=x;this.next=null;}}// With pointer initializationclassListNode{intval;publicListNodenext;publicListNode(intx){this.val=x;this.next=null;}}
Common Construction Methods
// Method 1: Manual constructionListNodecreateList(int[]values){if(values.length==0)returnnull;ListNodehead=newListNode=newnew(values[0]);ListNodecur=head;for(inti=1;i<values.length;++i){cur.next=newListNode=newnew(values[i]);cur=cur.next;}returnhead;}// Method 2: Recursive constructionListNodecreateListRecursive(int[]values,intindex){if(index>=values.length)returnnull;ListNodenode=newListNode=newnew(values[index]);node.next=createListRecursive(values,index+1);returnnode;}// Method 3: Using dummy nodeListNodecreateListWithDummy(int[]values){ListNodedummy=newListNode=newnew(0);ListNodecur=dummy;for(intval:values){cur.next=newListNode=newnew(val);cur=cur.next;}returndummy.next;}// Method 4: Create list from arrayListNodecreateListFromArray(intarr[],intn){if(n==0)returnnull;ListNodehead=newListNode=newnew(arr[0]);ListNodecur=head;for(inti=1;i<n;++i){cur.next=newListNode=newnew(arr[i]);cur=cur.next;}returnhead;}
Utility Functions
// Print linked list (for debugging)staticvoidprintList(ListNodehead){ListNodecur=head;while(cur!=null){cout<<cur.val;if(cur.next!=null)cout<<" . ";cur=cur.next;}cout<<endl;}// Get length of linked liststaticintgetLength(ListNodehead){intlength=0;ListNodecur=head;while(cur!=null){length++;cur=cur.next;}returnlength;}// Convert linked list to vectorint[]listToVector(ListNodehead){List<Integer>result=newArrayList<>();ListNodecur=head;while(cur!=null){result.add(cur.val);cur=cur.next;}returnresult;}// Delete entire linked list (free memory)staticvoiddeleteList(ListNodehead){while(head!=null){ListNodetemp=head;head=head.next;deletetemp;}}
Example Usage
// Example: Create list [1, 2, 3, 4, 5]int[]values={1,2,3,4,5}ListNodehead=createList(values);// Print the list printList = new list(head); // Output: 1 . 2 . 3 . 4 . 5// Get lengthintlen=getLength(head);// len = 5// Convert to vectorint[]vec=listToVector(head);// vec = [1, 2, 3, 4, 5]// Clean up deleteList = new up(head);
Basic Operations
When to use: You need to “visit every node”, “count nodes”, “find a value”, or “collect values into an array”. Also the foundation for insert/delete at arbitrary positions.
// Iterative traversalstaticvoidtraverse(ListNodehead){ListNodecur=head;while(cur!=null){// Process cur.valcur=cur.next;}}// Recursive traversalstaticvoidtraverseRecursive(ListNodehead){if(head==null)return;// Process head.val traverseRecursive = new val(head.next);}
Insertion
// Insert at headListNodeinsertAtHead(ListNodehead,intval){ListNodenewNode=newListNode=newnew(val);newNode.next=head;returnnewNode;}// Insert after nodestaticvoidinsertAfter(ListNodenode,intval){ListNodenewNode=newListNode=newnew(val);newNode.next=node.next;node.next=newNode;}
Deletion
// Delete node (given node to delete, not head)staticvoiddeleteNode(ListNodenode){node.val=node.next.val;node.next=node.next.next;}// Delete node with valueListNodedeleteNode(ListNodehead,intval){if(head==null)returnnull;if(head.val==val)returnhead.next;ListNodecur=head;while(cur.next!=null){if(cur.next.val==val){cur.next=cur.next.next;break;}cur=cur.next;}returnhead;}
When to use: The problem says “middle of list”, “kth from end”, “intersection of two lists”, or “split list into halves”. Use fast/slow pointers to solve in one pass without knowing the length.
// Find middle nodeListNodefindMiddle(ListNodehead){ListNodeslow=head;ListNodefast=head;while(fast!=null&&fast.next!=null){slow=slow.next;fast=fast.next.next;}returnslow;}// Find kth node from endListNodefindKthFromEnd(ListNodehead,intk){ListNodefast=head;for(inti=0;i<k;++i){if(fast==null)returnnull;fast=fast.next;}ListNodeslow=head;while(fast!=null){slow=slow.next;fast=fast.next;}returnslow;}
Two Pointers for Partitioning
// Partition list around value xListNodepartition(ListNodehead,intx){ListNodeless=newListNode=newnew(0);ListNodegreater=newListNode=newnew(0);ListNodelessCur=less;ListNodegreaterCur=greater;while(head!=null){if(head.val<x){lessCur.next=head;lessCur=lessCur.next;}else{greaterCur.next=head;greaterCur=greaterCur.next;}head=head.next;}greaterCur.next=null;lessCur.next=greater.next;returnless.next;}
When to use: The problem involves “delete head”, “merge lists”, “insert at front”, or any operation where the head might change. A dummy node in front of head eliminates null-check edge cases.
// Remove elements with dummy nodeListNoderemoveElements(ListNodehead,intval){ListNodedummy=newListNode=newnew(0);dummy.next=head;ListNodecur=dummy;while(cur.next!=null){if(cur.next.val==val){cur.next=cur.next.next;}else{cur=cur.next;}}returndummy.next;}
When to use: The problem says “reverse linked list”, “reverse between positions”, “reverse in groups of k”, or “palindrome linked list”. The core trick is rewiring next pointers as you walk.
// Reverse nodes from position left to rightListNodereverseBetween(ListNodehead,intleft,intright){ListNodedummy=newListNode=newnew(0);dummy.next=head;prev=dummy;// Move to left positionfor(inti=1;i<left;++i){prev=prev.next;}// ReverseListNodecur=prev.next;for(inti=0;i<right-left;++i){ListNodenext=cur.next;cur.next=next.next;next.next=prev.next;prev.next=next;}returndummy.next;}
Reverse in Groups
// Reverse nodes in k-groupListNodereverseKGroup(ListNodehead,intk){ListNodecur=head;intcount=0;while(cur!=null&&count<k){cur=cur.next;count++;}if(count==k){cur=reverseKGroup(cur,k);while(count-->0){ListNodenext=head.next;head.next=cur;cur=head;head=next;}head=cur;}returnhead;}
When to use: The problem says “merge two sorted lists”, “merge k sorted lists”, or “add two numbers represented as lists”. Compare heads, advance the smaller, and use a dummy node to collect the result.
// Merge two sorted listsListNodemergeTwoLists(ListNodelist1,ListNodelist2){ListNodedummy=newListNode=newnew(0);ListNodecur=dummy;while(list1!=null&&list2!=null){if(list1.val<=list2.val){cur.next=list1;list1=list1.next;}else{cur.next=list2;list2=list2.next;}cur=cur.next;}cur.next=(list1!=null)?list1:list2;returndummy.next;}
Merge K Sorted Lists
// Merge k sorted lists using divide and conquerListNodemergeKLists(ListNode[]lists){if(lists.length==0)returnnull;returnmergeKListsHelper(lists,0,lists.size()-1);}ListNodemergeKListsHelper(ListNode[]lists,intleft,intright){if(left==right)returnlists[left];intmid=left+(right-left)/2;ListNodeleftList=mergeKListsHelper(lists,left,mid);ListNoderightList=mergeKListsHelper(lists,mid+1,right);returnmergeTwoLists=newreturn(leftList,rightList);}
When to use: The problem asks “has cycle”, “find cycle start”, or “find the duplicate number” (which reduces to cycle detection). Floyd’s algorithm: if fast and slow meet, there’s a cycle.
When to use: The problem mentions “circular linked list”, “sorted circular list”, or “rotate list”. The key difference from normal lists: the tail’s next points back to the head instead of nullptr.
// Insert into sorted circular linked listListNodeinsert(ListNodehead,intinsertVal){if(head==null){ListNodenewNode=newListNode=newnew(insertVal);newNode.next=newNode;returnnewNode;}ListNodeprev=head;ListNodecur=head.next;while(cur!=head){// Normal insertion pointif(prev.val<=insertVal&&insertVal<=cur.val){break;}// At the boundary (largest to smallest)if(prev.val>cur.val&&(insertVal>=prev.val||insertVal<=cur.val)){break;}prev=cur;cur=cur.next;}prev.next=newListNode=newnew(insertVal);prev.next.next=cur;returnhead;}