Bea.AI coding blog
  • Tree
    • Tree Traverse
    • Iteration based traverse
    • Typical problems and solutions
      • Max width of binary tree
      • Binary Tree & BST Serialize & Deserialize
      • Lowest common ancestor (LCA) for Binary Tree and BST
      • Subproblem-based Approach for Resolving Max Value on Trees
      • Path sum III
  • Graph
  • Data structure
    • Java data structure
  • Algorithm general templates
    • Tree
    • Trie
    • Graph
  • Java Algorithm Tips and Tricks
    • Java concurrent list
  • Coding patterns & Strategies
  • Coding patterns & template
    • 1. Binary Search
    • 2. Two Pointer
    • 3. Sliding Window
    • 4. Backtracking
    • 5. DFS
    • 6. BFS
    • 7. Stack
    • 8. Heap
    • 9. Prefix Sum
    • 10. Linked List
    • 11. BST
    • 12. Line sweep
    • 14. Tree
    • 15. Graph
    • 16. Bit manipulation
    • 17. Matrix
    • 18. Monotonic Stack
    • 19. Sorting
    • 20. Union Find
    • 21. Trie
    • 22. Dynamic programming
    • 23. Customized Data Structure
  • Code interview steps
  • Leetcode
    • Tree
      • Traversal
      • Construction and Conversion
      • Search and Validation
      • Manipulation and Modification
      • Special Trees
      • Miscellaneous
    • Dynamic programing
      • Classic DP Problems
      • Sequence/Array DP
      • Matrix DP
      • Knapsack Problems
      • String DP
      • Tree/Graph DP
      • Optimization Problems
      • Combinatorial DP
    • DFS
      • Graph Traversal
      • Path Finding
      • Tree Traversal
      • Backtracking
      • Topological Sorting
      • Traversal Order
      • Dynamic Programming with DFS
      • Connected Components
    • BFS
      • Graph
      • Tree
      • Matrix
      • String
      • Others
    • Two points
      • Array
      • String
      • Linked List
      • Sorting
      • Others
    • LinkedList
      • Basic Operations
      • Cycle Detection and Handling
      • Intersection and Union
      • Partitioning and Merging
      • Palindrome
      • Miscellaneous
    • Backtracking
    • Binary Search
    • Union Find
    • Trie
    • Sort
    • Heap
    • Randomness
    • Topological sort
    • Stack
    • HashTable
    • Sliding Window
  • Blind 75
    • Array
    • Binary
    • Dynamic Programming
    • Graph
    • Interval
    • LinkedList
    • Matrix
    • String
    • Tree
    • Heap
  • Companies
    • Apple
Powered by GitBook
On this page
  • 11. Intersection of Two Linked Lists
  • 12. Union of Two Linked Lists
  • 13. Merge k Sorted Lists
  • 14. Convert Sorted List to Binary Search Tree
  • 15. Flatten a Multilevel Doubly Linked List
  1. Leetcode
  2. LinkedList

Intersection and Union

11. Intersection of Two Linked Lists

  1. Problem Description: The problem "Intersection of Two Linked Lists" on LeetCode asks us to find the node at which two singly linked lists intersect. We are given two linked lists, and we need to return the intersecting node if the lists intersect, or return null if they don't intersect.

Link to the problem on LeetCode: https://leetcode.com/problems/intersection-of-two-linked-lists/

  1. Optimized Java Code with Detailed Comments:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        // Base case: If either of the lists is null, there is no intersection
        if (headA == null || headB == null) {
            return null;
        }
        
        ListNode currA = headA;
        ListNode currB = headB;
        
        // Traverse both lists until they intersect or reach the end
        while (currA != currB) {
            // If we reach the end of list A, move to the head of list B
            if (currA == null) {
                currA = headB;
            } else {
                currA = currA.next;
            }
            
            // If we reach the end of list B, move to the head of list A
            if (currB == null) {
                currB = headA;
            } else {
                currB = currB.next;
            }
        }
        
        // Return the intersecting node (or null if there is no intersection)
        return currA;
    }
}
  1. Algorithm and Approach: To find the intersection point of two linked lists, we can use a two-pointer approach.

  2. Start by initializing two pointers, currA and currB, to the heads of the input lists headA and headB, respectively.

  3. Traverse both lists simultaneously by advancing currA and currB one step at a time.

  4. When currA reaches the end of list A, move it to the head of list B and continue traversing.

  5. Similarly, when currB reaches the end of list B, move it to the head of list A and continue traversing.

  6. The intersection point, if it exists, is the node at which currA and currB meet.

  7. If there is no intersection, currA and currB will both reach the end of their respective lists at the same time, and we return null.

During an interview, it is important to communicate your approach step by step, explaining the reasoning behind your solution. Highlight the fact that the two lists may have different lengths and that this approach can handle that scenario. Additionally, mention the optimization achieved by reusing the lists' nodes rather than creating a new data structure.

12. Union of Two Linked Lists

Sure, I can help with that.

  1. Problem Description: The problem "Union of Two Linked Lists" asks us to find the union of two given linked lists. The union of two lists is a new list that contains all the distinct elements from the original two lists. The order of elements in the union list should be the same as they appear in the original lists.

Here is the link to the problem on LeetCode: https://leetcode.com/problems/intersection-of-two-linked-lists/

  1. Optimized Java Code:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */

public class UnionOfTwoLinkedLists {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        Set<Integer> uniqueElements = new HashSet<>();
        ListNode pointerA = headA;
        ListNode pointerB = headB;
        
        // Add all elements from list A to the set
        while (pointerA != null) {
            uniqueElements.add(pointerA.val);
            pointerA = pointerA.next;
        }
        
        // Add all elements from list B to the set
        while (pointerB != null) {
            uniqueElements.add(pointerB.val);
            pointerB = pointerB.next;
        }
        
        // Create the union list
        ListNode dummyHead = new ListNode(0);
        ListNode current = dummyHead;
        
        for (int element : uniqueElements) {
            current.next = new ListNode(element);
            current = current.next;
        }
        
        return dummyHead.next;
    }
}
  1. Algorithm Explanation: To solve this problem, we can use a hash set to store the unique elements from both lists. We iterate through each list separately and add each element to the set. Since a set ensures unique elements, the duplicates will automatically be removed.

After populating the set with all the unique elements, we create a new linked list and add the elements from the set in the order they appear. We iterate through the set and create a new node for each element, linking them together.

In the end, we return the head of the new union list.

During an interview process, it's important to break down the problem into smaller steps and explain each step clearly to the interviewer. It's also crucial to think about edge cases and test the algorithm with different inputs to ensure it works correctly. Additionally, discussing the time and space complexity of the algorithm is important to evaluate its efficiency.

I hope this helps! Let me know if you have any further questions.

13. Merge k Sorted Lists

  1. Problem Description:

The problem can be found on LeetCode with the following link: https://leetcode.com/problems/merge-k-sorted-lists/

The problem asks us to merge k sorted linked lists and return it as one sorted list.

  1. Optimized Java Code:

Here is the optimized Java code for the "Merge k Sorted Lists" problem on LeetCode:

import java.util.PriorityQueue;

public class MergeKSortedLists {
    
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }
        
        PriorityQueue<ListNode> pq = new PriorityQueue<>((a, b) -> a.val - b.val);
        
        // Add all the first nodes of the lists to the priority queue
        for (ListNode list : lists) {
            if (list != null) {
                pq.offer(list);
            }
        }
        
        ListNode dummy = new ListNode(0);
        ListNode curr = dummy;
        
        // Process the nodes in the priority queue
        while (!pq.isEmpty()) {
            ListNode nextNode = pq.poll();
            curr.next = nextNode;
            curr = curr.next;
            
            if (nextNode.next != null) {
                pq.offer(nextNode.next);
            }
        }
        
        return dummy.next;
    }
    
}
  1. Algorithm Explanation:

The problem requires us to merge k sorted linked lists. One simple approach is to merge the lists one by one, but this can be an inefficient solution with a time complexity of O(k * n^2) where n is the average length of the lists.

To optimize the solution, we can use a priority queue, which can be implemented as a min-heap in Java. We will keep adding the first node of each list to the priority queue. The priority queue will automatically sort the nodes based on their values.

We start by adding all the first nodes of the linked lists to the priority queue. Then, we create a dummy node to build our result list and a current pointer to keep track of the last node of the result list.

In each iteration, we extract the smallest node from the priority queue and append it to the result list. If the extracted node has a next node, we add the next node to the priority queue. We repeat this process until the priority queue is empty.

Finally, we return the head of the merged list, which is stored in the dummy node's next pointer.

During an interview, an interviewer may ask to implement this problem using an optimized approach, like using a priority queue. They may also ask you to analyze the time and space complexity of your solution. It's important to explain and justify your code choices and communicate your thought process clearly.

14. Convert Sorted List to Binary Search Tree

  1. Problem Description and Link: The problem "Convert Sorted List to Binary Search Tree" on Leetcode asks us to convert a singly linked list into a balanced binary search tree.

Link to the problem: https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/

  1. Optimized Java code for the problem "Convert Sorted List to Binary Search Tree" with detailed comments:

// Definition for singly-linked list.
class ListNode {
    int val;
    ListNode next;

    ListNode(int val) {
        this.val = val;
        this.next = null;
    }
}

// Definition for a binary tree node.
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int val) {
        this.val = val;
        this.left = null;
        this.right = null;
    }
}

class Solution {
    public TreeNode sortedListToBST(ListNode head) {
        if (head == null) {
            return null;
        }

        return convertToBST(head, null);
    }

    private TreeNode convertToBST(ListNode head, ListNode tail) {
        if (head == tail) {
            return null;
        }

        // Find the middle node of the linked list
        ListNode mid = findMiddle(head, tail);

        // Create a new node with the value of the middle element
        TreeNode node = new TreeNode(mid.val);

        // Recursively construct the left and right subtrees
        node.left = convertToBST(head, mid);
        node.right = convertToBST(mid.next, tail);

        return node;
    }

    private ListNode findMiddle(ListNode head, ListNode tail) {
        ListNode slow = head;
        ListNode fast = head;

        while (fast != tail && fast.next != tail) {
            slow = slow.next;
            fast = fast.next.next;
        }

        return slow;
    }
}
  1. Algorithm Explanation and Interview Process Insights:

Approaching this problem, there are a few key points to consider:

  • The linked list is sorted in ascending order, which suggests that the middle element of the list will be the root of the BST to be constructed.

  • To maintain the balance of the BST, we can recursively convert the left and right halves of the linked list into the left and right subtrees of the BST.

  • To find the middle element efficiently, we can use the "two-pointer" technique, where one pointer moves one step at a time while the other pointer moves two steps at a time. This will ensure that the slow pointer reaches the middle element when the fast pointer reaches the end of the list or the next of the end.

During an interview process, it is crucial to understand and explain the given problem clearly. Here is a step-by-step breakdown of the problem-solving approach:

  1. Understand the problem requirements and constraints.

  2. Visualize the problem by breaking it down into smaller components.

  3. Identify the potential algorithmic approach.

  4. Start implementing the code skeleton while ensuring to add proper comments.

  5. Test the solution with several test cases, including base cases and edge cases, to ensure correctness.

  6. Optimize the solution if possible, considering time complexity and space complexity.

When explaining the problem and solution during an interview, it is crucial to communicate your thought process and overall understanding of the problem. This includes discussing the approach, algorithm, and optimizations, if any. Additionally, it's beneficial to clarify any assumptions made and ask for feedback or suggestions from the interviewer.

15. Flatten a Multilevel Doubly Linked List

  1. Problem Description:

The problem "Flatten a Multilevel Doubly Linked List" asks us to flatten a given multilevel doubly linked list. The multilevel linked list contains nodes which can also have child nodes, forming a nested structure. Our task is to flatten this nested structure into a single-level doubly linked list.

Problem Link: https://leetcode.com/problems/flatten-a-multilevel-doubly-linked-list/

  1. Optimized Java Code:

Below is the optimized Java code for the problem "Flatten a Multilevel Doubly Linked List" with detailed comments:

class Solution {
    public Node flatten(Node head) {
        Node curr = head;
        
        while (curr != null) {
            if (curr.child == null) {
                curr = curr.next; // Move to the next node if no child
                continue;
            }
            
            // Find the tail of the child list and connect it to the next node after curr
            Node child = curr.child;
            while (child.next != null) {
                child = child.next;
            }
            
            child.next = curr.next;
            if (curr.next != null) {
                curr.next.prev = child;
            }
            
            curr.next = curr.child;
            curr.child.prev = curr;
            curr.child = null; // Remove the child reference
            
            curr = curr.next; // Move to the next node
        }
        
        return head;
    }
}
  1. Algorithm and Approach:

During an interview, it is important to approach this problem step-by-step, making sure to communicate your thoughts and verify your understanding of the problem statement. Here is a detailed description of the algorithm and how to think through it during the interview process:

  • Initialize a pointer curr to the head of the linked list.

  • Iterate through the linked list using the curr pointer, until reaching the end of the list.

  • For each node curr, check if it has a child node.

  • If curr does not have a child node, move curr to the next node and continue the iteration.

  • If curr has a child node, we need to flatten the child list and connect it to the next node.

  • To flatten the child list, find the tail of the child list by iterating from the child node until reaching the last node of the child list.

  • Connect the tail of the child list to the next node of curr.

  • If the next node of curr is not null, update the previous pointer of the next node to point to the tail of the child list.

  • Connect the child node to curr by updating the next pointer of curr to point to the child node and the previous pointer of the child node to point to curr.

  • Remove the child reference by setting curr.child to null.

  • Move curr to the next node and continue the iteration.

  • After iterating through the entire linked list, return the head of the flattened list.

This approach has a time complexity of O(N), where N is the total number of nodes in the linked list.

PreviousCycle Detection and HandlingNextPartitioning and Merging

Last updated 1 year ago