My DSA Grind β Day 5 Solutions


π Table of Contents
- Introduction
Problems List
Longest Common Prefix
Delete Node in a Linked List
Remove Nth Node from the End of List
Reverse Linked List
Merge Two Sorted Lists
- Conclusion
β¨ Introduction
Welcome to Day 5 of my 90 Days DSA Challenge!
Today, I focused on mastering some important string and linked list problems which are commonly asked in interviews. These problems tested my understanding of pointer manipulation, string traversal, and edge case handling.
1οΈβ£ Longest Common Prefix
β Approach & Logic
πΉ Method 1: Pairwise Comparison (Prefix Shrinking)
Start with the prefix length as the first string's length.
Compare each pair of strings in the array.
For each pair, check how long the prefix matches.
Update the minimum prefix length after each comparison.
Finally, return the substring from
0
tominLen
.
π§ Why this works:
We shrink the valid prefix length with each pairwise mismatch, so we end up with the exact max match length.
πΉ Method 2: Vertical Scanning (Character-by-Character)
First, find the minimum string length among all strings.
Then loop index by index (i.e., vertically), comparing each character at the same position across all strings.
The moment a mismatch is found, return the substring up to that index.
If no mismatch is found, return the substring from 0 to
minLen
.
π§ Why this works:
Since all strings must match character-by-character from the beginning, this method directly checks the common prefix across all strings simultaneously.
π Dry Run / Key Observations
π§ͺ Input: ["flower", "flow", "flight"]
Method 1:
Initial
minLen = 6
(length of"flower"
)Compare
"flower"
and"flow"
β common"flow"
βj=4
Update
minLen = 4
Compare
"flow"
and"flight"
β compare up to index 4 β common"fl"
βj=2
Final
minLen = 2
β Return"fl"
Method 2:
minLen = 4
(shortest string is"flow"
)i = 0 β
'f'
matches for all β continuei = 1 β
'l'
matches for all β continuei = 2 β
"flight"
has'i'
, but others have'o'
β mismatchReturn
"fl"
π¨ Physical Representation
Letβs visualize Method 2:
pgsqlCopyEditInput: ["flower", "flow", "flight"]
Index: 0 1 2 3 4 5
-----------------------------
flower f l o w e r
flow f l o w
flight f l i g h t
Step 1: Compare column 0 β all 'f' β
Step 2: Compare column 1 β all 'l' β
Step 3: Compare column 2 β 'o' β 'i' β β return "fl"
π Edge Cases Handled
β Array of size 1 β return that string
β No common prefix β return
""
β All strings are the same β return the string
β Empty strings inside array β return
""
β Different length strings β handled via
minLen
π‘ What I Learned
I learned two efficient ways to solve the Longest Common Prefix problem:
Shrinking the prefix by pairwise comparison
Vertical scanning across all strings character-by-character.
This problem showed me the importance of both horizontal and vertical traversal strategies in string problems.
2οΈβ£ Delete Node in a Linked List
Example 1:
Input: head = [4,5,1,9], node = 5
Output: [4,1,9]
Explanation: You are given the second node with value 5, the linked list should become 4 -> 1 -> 9 after calling your function.
Example 2:
Input: head = [4,5,1,9], node = 1
Output: [4,5,9]
Explanation: You are given the third node with value 1, the linked list should become 4 -> 5 -> 9 after calling your function.
Constraints:
The number of the nodes in the given list is in the range
[2, 1000]
.-1000 <= Node.val <= 1000
The value of each node in the list is unique.
The
node
to be deleted is in the list and is not a tail node.
β Approach & Logic
We're given only a reference to the node that needs to be deleted, not the head of the list.
To delete a node in a singly linked list, you usually need access to the previous node. But here, we donβt have that.
So, the trick is:
π Copy the data from the next node to the current node,
β‘οΈ then skip over the next node by updating thenext
pointer.
β Steps:
node.val =
node.next
.val
β overwrite current nodeβs value with the next nodeβs value.node.next
=
node.next.next
β skip the next node, effectively deleting it.
π§ We're not really deleting the node we were given β we're copying the next one into it and deleting that one!
class Solution {
public void deleteNode(ListNode node) {
node.val=node.next.val;
node.next=node.next.next;
}}
π Dry Run / Key Observations
π§ͺ Input Linked List:
1 β 2 β 3 β 4 β 5
β
node to delete
Step-by-Step:
node = 3
node.val =
node.next
.val
β node becomes4
node.next
=
node.next.next
β skip4
, now list is:
1 β 2 β 4 β 5
Result: node 3
has been replaced by 4
, and the original 4
is gone.
π¨ Physical Representation
Before:
Head β 1 β 2 β 3 β 4 β 5
β
node to delete
After:
Head β 1 β 2 β 4 β 5
The node with value
3
now acts like the node with value4
.The original
4
node is removed from the chain.
π Edge Cases Handled
- π« Youβre guaranteed that the node to be deleted is not the tail, so we donβt need to handle null checks for
node.next
.
π‘ What I Learned
I learned a clever in-place trick to delete a node in a linked list without access to the head. Instead of deleting the node directly, I learned how to copy and bypass the next node to simulate deletion.
3οΈβ£ Remove Nth Node From the End of List
Given the head
of a linked list, remove the n<sup>th</sup>
node from the end of the list and return its head.
Example 1:
Input: head = [1,2,3,4,5], n = 2
Output: [1,2,3,5]
Example 2:
Input: head = [1], n = 1
Output: []
Example 3:
Input: head = [1,2], n = 1
Output: [1]
Constraints:
The number of nodes in the list is
sz
.1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
β Approach & Logic
β¨ Method 1: Two Pass Approach (Find Length First)
We first calculate the total length of the linked list, then determine the position from the front using length - n
.
β Steps:
Traverse the list once to calculate its length (
len
).Create a dummy node and link it to the head (to handle edge cases like removing the head itself).
Start from dummy and move
len - n
times to reach the previous node of the one to be deleted.Modify the
next
pointer to skip the nth node.Return
dummy.next
as the new head.
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
int len=0;
ListNode cur =head;
while(cur!=null){
cur=cur.next;
len=len+1;
}
ListNode dummy=new ListNode(0);
dummy.next=head;
ListNode prev=dummy;
int jumps=len-n;
while(jumps>0){
prev=prev.next;
jumps=jumps-1;
}
prev.next=prev.next.next;
return dummy.next;
β¨ Method 2: One Pass Approach (Two Pointers)
This is a more optimized solution using two pointers β fast and slow β to do the job in a single pass.
β Steps:
Move the
fast
pointern
steps ahead.Start both
fast
andslow
from dummy (before head).Move both pointers one step at a time until
fast
reaches the end.Now
slow
will be right before the node to be deleted.Remove that node by skipping its pointer.
Return
dummy.next
.
int currjumps=n;
ListNode cur=head;
while(currjumps!=0){
cur=cur.next;
currjumps=currjumps-1;
}
ListNode dummy=new ListNode(0);
dummy.next=head;
ListNode prev=dummy;
while(cur!=null)
{
cur=cur.next;
prev=prev.next;
}
prev.next=prev.next.next;
return dummy.next;
π Dry Run / Key Observations
Input:
javaCopyEdithead = [1, 2, 3, 4, 5], n = 2
π§ͺ Method 1 Dry Run:
Full length = 5
Position to delete from front =
5 - 2 = 3
Go 3 steps from dummy β reach node with value 3
Skip next (node 4) β result:
[1, 2, 3, 5]
π§ͺ Method 2 Dry Run:
Move
fast
2 steps β now at node 3Start
slow
at dummyMove both until
fast
reaches endslow
will be at node 3Skip node 4 β result:
[1, 2, 3, 5]
π¨ Physical Representation
Initial List:
cssCopyEdit[1] -> [2] -> [3] -> [4] -> [5]
After Removing 2nd Node from End (Node with value 4):
cssCopyEdit[1] -> [2] -> [3] -> [5]
π Edge Cases Handled
β Removing the head node.
β Removing the last node.
β Removing when the list has only one node.
β Handles all using a dummy node for simplicity.
π‘ What I Learned
Using a dummy node helps elegantly handle edge cases.
Two-pass method is easier to understand but less efficient.
Single-pass method with two pointers is more optimized and elegant.
This is a classic pattern for problems like detecting/removing kth elements from the end in a list.
4οΈβ£ Reverse Linked List
Given the head
of a singly linked list, reverse the list, and return the reversed list.
Example 1:
Input: head = [1,2,3,4,5]
Output: [5,4,3,2,1]
Example 2:
Input: head = [1,2]
Output: [2,1]
Example 3:
Input: head = []
Output: []
Constraints:
- The number of nodes in the list is the range
[0, 5000]
.
-5000 <= Node.val <= 5000
β Approach & Logic
This is an iterative solution to reverse a linked list in-place using three pointers:
curr
β Points to the current node weβre processing.prev
β Tracks the previous node (initially null).next
β Temporarily stores the next node to not lose the link.
β Steps:
Start with
curr = head
,prev = null
Loop while
curr != null
:After the loop,
prev
will point to the new head of the reversed list.
π Dry Run / Key Observations
Input:
head = [1, 2, 3, 4, 5]
Iteration-wise Status:
Step | curr.val | next.val | prev.val | Action |
1 | 1 | 2 | null | Reverse link, move pointers |
2 | 2 | 3 | 1 | Reverse link, move pointers |
3 | 3 | 4 | 2 | Reverse link, move pointers |
4 | 4 | 5 | 3 | Reverse link, move pointers |
5 | 5 | null | 4 | Reverse link, move pointers |
Final Output:
[5] -> [4] -> [3] -> [2] -> [1]
class Solution {
public ListNode reverseList(ListNode head) {
ListNode curr=head;
ListNode prev=null;
while(curr!=null){
ListNode next=curr.next;
curr.next=prev;
prev=curr;
curr=next;
}
return prev;
}
}
π¨ Physical Representation with Diagrams
Initial List:
head β [1] β [2] β [3] β [4] β [5] β null
β
curr
prev = null
π Iteration 1:
curr = [1]
,next = [2]
,prev = null
Before Reversing:
prev = null
curr = [1] β [2] β [3] β [4] β [5] β null
Step:
After Reversing:
prev = [1] β null
curr = [2] β [3] β [4] β [5] β null
π Iteration 2:
curr = [2]
,next = [3]
,prev = [1]
Before Reversing:
prev = [1] β null
curr = [2] β [3] β [4] β [5] β null
Step:
next =
curr.next
β[3]
curr.next
= prev
β[2] β [1] β null
prev = curr
β[2]
curr = next
β[3]
After Reversing:
prev = [2] β [1] β null
curr = [3] β [4] β [5] β null
π Iteration 3:
curr = [3]
,next = [4]
,prev = [2]
Before Reversing:
prev = [2] β [1] β null
curr = [3] β [4] β [5] β null
Step:
next =
curr.next
β[4]
curr.next
= prev
β[3] β [2] β [1] β null
prev = curr
β[3]
curr = next
β[4]
After Reversing:
prev = [3] β [2] β [1] β null
curr = [4] β [5] β null
π Iteration 4:
curr = [4]
,next = [5]
,prev = [3]
Before Reversing:
prev = [3] β [2] β [1] β null
curr = [4] β [5] β null
Step:
next =
curr.next
β[5]
curr.next
= prev
β[4] β [3] β [2] β [1] β null
prev = curr
β[4]
curr = next
β[5]
After Reversing:
prev = [4] β [3] β [2] β [1] β null
curr = [5] β null
π Iteration 5:
curr = [5]
,next = null
,prev = [4]
Before Reversing:
prev = [4] β [3] β [2] β [1] β null
curr = [5] β null
Step:
next =
curr.next
βnull
curr.next
= prev
β[5] β [4] β [3] β [2] β [1] β null
prev = curr
β[5]
curr = next
βnull
After Reversing:
prev = [5] β [4] β [3] β [2] β [1] β null
curr = null
β Final Output:
return prev; // head of the new reversed list
[5] β [4] β [3] β [2] β [1] β null
π Edge Cases Handled
β Empty list (
head == null
)β Single element list (automatically reversed)
β Multiple elements
π‘ What I Learned
Reversing a linked list can be done in O(n) time and O(1) space using just three pointers.
Pointer manipulation is key in linked list problems β store the next node before changing any link!
This is a foundational problem for mastering linked list manipulation and recursion alternatives.
5οΈβ£ Merge Two Sorted Lists
You are given the heads of two sorted linked lists list1
and list2
.
Merge the two lists into one sorted list. The list should be made by splicing together the nodes of the first two lists.
Return the head of the merged linked list.
Example 1:
Input: list1 = [1,2,4], list2 = [1,3,4]
Output: [1,1,2,3,4,4]
Example 2:
Input: list1 = [], list2 = []
Output: []
Example 3:
Input: list1 = [], list2 = [0]
Output: [0]
Constraints:
The number of nodes in both lists is in the range
[0, 50]
.-100 <= Node.val <= 100
Both
list1
andlist2
are sorted in non-decreasing order.
β Approach & Logic
We use the Two Pointer Technique along with a dummy node to simplify the merging of two sorted linked lists.
Initialize a dummy node to act as the head of the merged list.
Use a
curr
pointer that always points to the last node in the merged list.Iterate through both
list1
andlist2
, picking the smaller value node and updating links.After one list ends, simply attach the remaining part of the other list to the merged list.
π§ Step-by-Step Code Explanation
ListNode dummy = new ListNode(0); // Dummy node to build result
ListNode curr = dummy; // Pointer to build the new list
while(list1 != null && list2 != null) {
if(list1.val < list2.val) {
curr.next = list1;
curr = list1;
list1 = list1.next;
} else {
curr.next = list2;
curr = list2;
list2 = list2.next;
}
}
// Add remaining elements
if(list1 == null) {
curr.next = list2;
} else {
curr.next = list1;
}
return dummy.next;
π¨ Physical Representation
Letβs say:
list1: [1] β [3] β [5]
list2: [2] β [4] β [6]
π Iteration 1:
list1.val = 1
,list2.val = 2
Pick
1
curr.next
= list1
β [0] β [1]curr = list1
list1 =
list1.next
π Iteration 2:
list1.val = 3
,list2.val = 2
Pick
2
curr.next
= list2
β [1] β [2]curr = list2
list2 =
list2.next
π Iteration 3:
list1.val = 3
,list2.val = 4
Pick
3
β [2] β [3]curr = list1
,list1 =
list1.next
π Continue...
Eventually:
Merged list: [1] β [2] β [3] β [4] β [5] β [6]
π§ First, the Concept:
Think of a linked list like a train, where each box is a node, and the connector between them is the .next
pointer.
When we say:
β
curr.next
= list1;
We're saying:
βConnect the next box of the current train to the front of list1.β
When we say:
β
curr = list1;
We're saying:
βNow move the current pointer to the box you just added.β
π― Why Do We Need Both?
Letβs say you're building a new train by choosing coaches from two existing trains (list1 and list2).
curr.next
= list1
:
You attach the next coach of your current train to a coach fromlist1
.curr = list1
:
Now that youβve added that coach, you need to move your hand forward to that new coach. Otherwise, the next addition will overwrite the same place!
π§ Without curr = list1
, you'd be stuck!
If you donβt update curr
, your pointer will stay on the same node. The next time you try to attach a node, itβll overwrite the .next
again!
π Dry Run Example
Input:
list1 = [1, 2, 4]
list2 = [1, 3, 4]
Output:
Merged List: [1, 1, 2, 3, 4, 4]
π Edge Cases Handled
One list is
null
and the other is not β It attaches the remaining non-null list.Both lists are
null
β Returns an empty list (null
).Lists with duplicate values β Theyβre preserved in sorted order.
π‘ What I Learned
Using a dummy node simplifies edge cases (like empty lists).
curr.next
= list1/list2
connects the node.curr = list1/list2
moves the pointer to the end of the merged list.Proper pointer movement is key in linked list problems.
β Conclusion for Blog (Day 5 - DSA Challenge)
As Day 5 of the 90 Days DSA Challenge comes to a close, I feel a deeper understanding and greater confidence building within me. Todayβs problems, ranging from string manipulation to advanced linked list operations, were not just coding exercisesβthey were logical puzzles that pushed my analytical thinking, attention to edge cases, and pointer manipulation.
Each problem taught me something crucial:
Longest Common Prefix sharpened my skills in string traversal and understanding boundary conditions.
Delete Node in a Linked List was a concise yet clever trick that reminded me how direct manipulation can save space and time.
Remove Nth Node from End pushed me to implement multiple approaches, ensuring robustness and flexibility in problem-solving.
Reverse a Linked List reinforced the importance of clear visual representation when dealing with pointer-based data structures.
Merge Two Sorted Lists highlighted how auxiliary nodes like
dummy
can simplify even the trickiest of scenarios.
π‘ With each problem, Iβm not just solving LeetCode questionsβIβm becoming more fluent in the language of logic, learning how to think like a software engineer.
Thank you for joining me on this journey. Letβs keep building momentum togetherβone problem at a time!
π¨βπ» β A. Saivaishnav, Final Year CSE
Subscribe to my newsletter
Read articles from Saivaishnav Ambati directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
