diff --git a/README.md b/README.md index b984c08..d0ab75b 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ For a glimpse into my journey and the projects I've been involved in, feel free - Linked Lists - Two-Pointer Approach - Reversing Linked Lists + - Merge Two Sorted Linked Lists - Developer Tools - My Development Environment: kitty, zsh, Neovim, tmux, and lazygit diff --git a/content/contents.md b/content/contents.md index 6123fdd..3b89ffc 100644 --- a/content/contents.md +++ b/content/contents.md @@ -42,5 +42,6 @@ summary: "Index of all content" - Linked Lists * Two-Pointer Approach * Reversing Linked Lists + * Merge Two Sorted Linked Lists - Developer Tools - My Development Environment: kitty, zsh, Neovim, tmux, and lazygit diff --git a/content/posts/dsa/merge-sorted-linked-lists/index.md b/content/posts/dsa/merge-sorted-linked-lists/index.md new file mode 100644 index 0000000..329dc35 --- /dev/null +++ b/content/posts/dsa/merge-sorted-linked-lists/index.md @@ -0,0 +1,205 @@ +--- +author: "Avnish" +title: "Merge Two Sorted Linked Lists" +date: "2024-01-29" +description: "Implement a mergeTwoLists function that takes the head nodes of two sorted linked lists as the input and returns the head of the merged linked list" +tags: ["data-structures", "linked-lists", "go", "neetcode-150", "leetcode-easy"] +categories: ["Data Structures"] +series: ["Data Structures and Algorithms"] +aliases: + ["merge-sorted-linked-lists"] +ShowToc: true +TocOpen: false +comments: false +cover: + image: "merge-sorted-linked-lists-cover.png" + linkFullImages: true + alt: "The mergeTwoLists function will return the head of the merged linked list given two sorted linked lists as input" + caption: "" + relative: false + responsiveImages: false +math: true +--- + +# Problem Statement +We have to implement the `mergeTwoLists` function that takes the `head` nodes of two sorted linked lists as input +and returns the `head` node of the merged linked list as the output. + +
+ +# Optimal Solution +To merge both linked lists we can use the two-pointer approach by maintaining an iterator on both linked lists and +comparing their values. The smaller value will be selected and inserted at the end of a new list. The result would +be a merged sorted linked list. + +If all the values from any one of the linked lists are added then the other linked list will be joined at the end of +the merged linked list. + + + +## Psuedo-code for the Optimal Solution +```text +if(linked_list2==nil){ + return linked_list1 +} else if(linked_list1==nil){ + return linked_list2 +} + +temp1 = linked_list1.head +temp2 = linked_list2.head +mergedLinkedList = LinkedList() +while(temp1!=nil and temp2!=nil){ + if (temp1.value < temp2.value){ + mergedLinkedList.insertAtEnd(temp1.value) + temp1=temp1.next + } else { + mergedLinkedList.insertAtEnd(temp2.value) + temp2=temp2.next + } +} + +if(temp1!=nil){ + mergedLinkedList.Add(temp1) +} else if(temp2!=nil){ + mergedLinkedList.Add(temp2) +} + +return mergedLinkedList +``` + +## Time Complexity Analysis +### Best Case Scenario +For the best case input i.e. either the first or second linked list is empty, the time complexity of the +solution is $O(1)$ because we are returning the non-empty linked list as the result. + +### Worst Case Scenario +In the worst-case scenario, we have to iterate over both the linked lists completely. +But since we are iterating them together using two pointers the time complexity will be determined by the length of +the larger linked list. + +So the total time complexity of the solution in the worst-case scenario will be $O(n)$ where $n$ is the size +of the larger linked list. + +## Space Complexity Analysis +The merged linked list will contain all the elements from both input lists (with repetition). If the length of both linked +lists is $m$ and $n$, the additional memory space required by the solution will be $O(m+n)$. + +## Code for the Optimal Solution +```Go +package main + +import "fmt" + +type ListNode struct { + Val int + Next *ListNode +} + +func Display(ln *ListNode){ + temp := ln + for(temp!=nil){ + fmt.Printf("%d->", temp.Val) + temp=temp.Next + } + fmt.Println() +} + +func InsertAtEnd(list *ListNode, value int)(*ListNode){ + if list==nil{ + list = &(ListNode{Val:value}) + } else { + temp := list + for(temp.Next!=nil){ + temp=temp.Next + } + temp.Next = &(ListNode{Val:value}) + } + return list +} + +func JoinLists(list1 *ListNode, list2 *ListNode)(*ListNode){ + // Joins list1 with list2 by the last node + temp := list1 + for(temp.Next!=nil){ + temp=temp.Next + } + temp.Next = list2 + return list1 +} + +func mergeTwoLists(list1 *ListNode, list2 *ListNode)(*ListNode){ + // Checking if any of the input lists are empty + if(list1==nil){ + return list2 + } else if(list2==nil) { + return list1 + } + + temp1 := list1 + temp2 := list2 + var mergedList *ListNode + + // Loop over both linked lists until one of them/both + // are empty + for((temp1!=nil)&&(temp2!=nil)){ + + // If the current value in the first list is smaller + // then add it to the merged linked list and vice versa + if(temp1.Val