Best Linked List Interview Questions for 2023 - IQCode

Introduction to Linked List

Linked List is a linear data structure that is similar to an array. The primary difference is that the elements are not stored in contiguous memory locations. Instead, a node in the linked list contains a data value and a pointer to the next node. In this article, we will understand the purpose of a Linked List, its advantages and disadvantages, representation, and a brief history.

Purpose of Linked List

Arrays are great for storing a fixed size of data, but when the size of data is unknown and can change dynamically, they are not suitable. Additionally, arrays cannot perform insertions and deletions efficiently. Here the linked list comes into the picture. Linked List behaves dynamically, and its size can change as per the requirement. It is frequently used to build linear data structures like stacks and queues. Linked List is much more convenient to insert and delete items as we don't have to move into elements in memory when compared to an array.

Advantages of Linked List

- Linked List is flexible, and it grows and shrinks dynamically during runtime. - No memory wastage in Linked List. - New nodes are efficiently added and deleted. - Linked List does not have a predetermined size.

Disadvantages of Linked List

- Linked List requires more memory. - Traversing a Linked List is slower compared to an array. - Reverse traversing is not possible in a singly linked list, but it is possible in a doubly-linked list.

Representation

In C, we represent a Node using a structure that contains data and a reference to the next node. In Java or C#, we can represent a Linked List as a class and Node as an inner class.

Brief History

Linked Lists are invented by Allen Newell, Cliff Shaw, and Herbert A. Simon of RAND Corporation in 1955-1956. The authors incorporated it into their Information Processing Language and utilized it to create early AI applications. Hans Peter Luhn recommended the use of Linked Lists in chained hash tables in an IBM memo in 1953.

Linked List Interview Questions for Freshers

How can we find the middle element of a singly Linked List without iterating the list more than once?

Converting a Binary Tree to a Doubly-Linked List

Code:


class Node:
    def __init__(self, val):
        self.val = val  
        self.left = None  
        self.right = None  

def convert_bt_to_dll(root):
    if root is None: 
        return root  
    
    if root.left:
        left_node = convert_bt_to_dll(root.left)  
        
        while left_node.right:
            left_node = left_node.right  
        
        left_node.right = root  
        root.left = left_node  
    
    if root.right:
        right_node = convert_bt_to_dll(root.right)  
        
        while right_node.left:
            right_node = right_node.left  
        
        right_node.left = root  
        root.right = right_node  
    
    return root  

Explanation:

This code uses recursion to traverse the binary tree. The function 'convert_bt_to_dll' takes the root of the binary tree as an input parameter and recursively converts the binary tree to a doubly-linked list. It first checks if the root is None. If it is, it returns the root. Then, it recursively calls the function on the left subtree and stores the result in 'left_node'. It then traverses to the rightmost node of 'left_node' to get the tail node of the doubly-linked list. It then sets the right node of 'left_node' to the current root node and sets the left node of the current root node to 'left_node'. It then recursively calls the function on the right subtree and stores the result in 'right_node'. It then traverses to the leftmost node of 'right_node' to get the head node of the doubly-linked list. It then sets the left node of 'right_node' to the current root node and sets the right node of the current root node to 'right_node'. It then returns the current root node.

Removing a Cycle from a Linked List in Python

To remove a cycle from a linked list in Python, we can use the Floyd's Cycle-Finding Algorithm also known as the "tortoise and hare" algorithm.

Code:


class Node:
    def __init__(self, data):
        self.data = data
        self.next = None
      
def removeCycle(head):
    if head == None or head.next == None:
        return None
  
    slow = head
    fast = head
 
    while True:
        slow = slow.next
 
        if fast.next != None:
            fast = fast.next.next
        else:
            return None
 
        if slow == None or fast == None:
            return None
 
        if slow == fast:
            break
 
    slow = head
  
    while (slow.next != fast.next):
        slow = slow.next
        fast = fast.next
 
    fast.next = None
 
    return head

The Floyd’s Cycle-Finding Algorithm is used to detect a loop in a linked list. Once a loop is detected, we can use another algorithm to remove it. This algorithm uses two pointers, one running slowly with one node at a time while the other pointer runs twice as fast. If there is a loop in the linked list the fast pointer will eventually meet the slow pointer. We can then traverse the linked list starting from the head node with both pointers and their next. When they both meet, we can break the loop.

Finding Similar Elements in Two Linked Lists

Assuming there are no duplicates in the linked lists, we can use a simple approach to find the similar elements in them.

We can iterate over the elements of the first linked list and for each element, we can compare it with the elements of the second linked list. If a match is found, we can add that element to a new linked list.

Here's the implementation of this algorithm in Python:


class Node:
    def __init__(self, data=None):
        self.data = data
        self.next = None

class LinkedList:
    def __init__(self):
        self.head = None
    
    def append(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
        else:
            current_node = self.head
            while current_node.next:
                current_node = current_node.next
            current_node.next = new_node
    
    def print_list(self):
        current_node = self.head
        while current_node:
            print(current_node.data, end=" ")
            current_node = current_node.next
        print("\n")
        
def find_similar_elements(list1, list2):
    similar_list = LinkedList()
    current_node = list1.head
    while current_node:
        if current_node.data in list2.__dict__.values():
            similar_list.append(current_node.data)
        current_node = current_node.next
    return similar_list

We create a `Node` and `LinkedList` class. The `LinkedList` class has a `print_list` method to print the elements of the linked list. The `find_similar_elements` function takes in two linked lists as parameters and returns a new linked list of the similar elements between them.

We iterate over the elements of the first linked list `list1` and check if each element is present in the second linked list `list2`. If a match is found, we add that element to the `similar_list` linked list. Finally, we return the `similar_list` linked list.

Note that we have used the `__dict__.values()` method on `list2` to get a list of all the data elements of the list. This is because we have assumed that there are no duplicate elements in the linked list.

Why is Merge Sort a Better Option than Quicksort for Linked Lists?

When it comes to sorting data in a linked list, Merge Sort proves to be a better option as compared to Quicksort. This is because Merge Sort has a time complexity of O(n log n) which remains the same for both arrays and linked lists. Whereas, the time complexity of Quicksort is O(n^2) in the worst case scenario, making it inefficient for linked lists.

Moreover, Merge Sort utilizes the divide and conquer strategy, which makes it easier to sort linked lists. It does so by dividing the linked list into two halves, recursively sorting them and then merging them together.

Quicksort, on the other hand, works by selecting a pivot element, rearranging the elements such that elements smaller than the pivot are to its left and larger elements are to its right and then recursively applying the same process on the left and right subarrays. This process becomes difficult to implement on linked lists, as searching for elements and rearranging pointers can cause performance issues.

Therefore, Merge Sort is a better option than Quicksort for sorting linked lists due to its efficient time complexity and ease of implementation.

Program to Delete Odd-Positioned Nodes from a Circular Linked List


/*
 * A node of the circular linked list.
 */
class Node {
  int data;
  Node next;

  Node(int data) {
    this.data = data;
    next = null;
  }
}

/*
 * Function to delete odd-positioned nodes from a circular linked list.
 */
public void deleteOddNodes(Node head) {
  Node current = head;
  Node prev = null;
  int index = 1;
 
  // Traverse the circular linked list and delete odd-positioned nodes.
  while (current != null) {
    if (index % 2 != 0) { // Delete odd-positioned node.
      if (current == head) { // If current node is head.
        // Move to last node of the linked list.
        Node temp = head;
        while (temp.next != head) {
          temp = temp.next;
        }
        // Update the head and previous pointers.
        head = current.next;
        temp.next = head;
        prev = temp;
      } else { // If current node is not head.
        prev.next = current.next;
      }
      // Delete the current node.
      current = current.next;
    } else { // Keep even-positioned node.
      prev = current;
      current = current.next;
    }
    index++;
  }
}

The above program uses a class `Node` to represent a node in the circular linked list. In the `deleteOddNodes` function, we traverse the circular linked list and delete nodes at odd positions (1-based indexing), while keeping the nodes at even positions. We also update the pointers of the linked list accordingly.

Extracting all leaves from a binary tree into a doubly linked list (DLL)

Code:

python

class Node:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None

def extract_leaves(root):
    # Function to extract leaves from a binary tree and return them as a doubly linked list (DLL)
    # Input: root - Root node of the binary tree
    # Output: tail - Tail node of the DLL

    if not root:
        return None

    if not root.left and not root.right:
        # Leaf node. Remove it from the tree and return as DLL node
        return root

    left_tail = extract_leaves(root.left)
    right_tail = extract_leaves(root.right)

    if left_tail:
        # Connect the leaf nodes from the left and right subtrees to the root
        left_tail.right = root.right
        if root.right:
            root.right.left = left_tail
        root.right = root.left
        root.left = None

    # Return the tail node of the merged DLL
    if right_tail:
        return right_tail
    else:
        return left_tail

This code defines a function "extract_leaves" that takes the root node of a binary tree as input and returns the tail node of a doubly linked list containing all the leaf nodes of the tree.

The function works by recursively calling itself on the left and right children of the root node, until a leaf node is reached. The leaf node is removed from the tree and returned as a node in the DLL.

The remaining non-leaf nodes are then connected to the leaf nodes from the left and right subtrees to form the DLL.

Converting a 2D matrix to a Linked List


class Node:
    def __init__(self, val):
        self.val = val
        self.right = None
        self.down = None

def convert_matrix_to_linked_list(matrix):
    rows = len(matrix)
    cols = len(matrix[0])
    
    # Creating nodes for each element in the matrix
    nodes = [[Node(matrix[i][j]) for j in range(cols)] for i in range(rows)]
    
    # Linking nodes to their right and down elements
    for i in range(rows):
        for j in range(cols):
            if j < cols-1:
                nodes[i][j].right = nodes[i][j+1]
            if i < rows-1:
                nodes[i][j].down = nodes[i+1][j]
    
    # Starting from the top-left node and displaying the linked list
    current = nodes[0][0]
    while current:
        print(current.val, end=" ")
        current = current.right if current.right else current.down

The above code defines a Node class having a value and pointers to right and down nodes. The

convert_matrix_to_linked_list

function takes a 2D matrix and returns a linked list where each node is linked to its next right and down node. This is achieved by first creating nodes for each element in the matrix and then linking them to their right and down elements. Finally, the linked list is displayed starting from the top-left node.

Finding Pairs in a Doubly-Linked List

This program is designed to find pairs in a sorted doubly-linked list of positive, distinct entries that add up to a provided value 'val'. The program accomplishes this task without using any extra memory space. It has an expected time complexity of O(N) and an expected space complexity of O(1).


// Define the Node class for a doubly-linked list
class Node {
    int data;
    Node next, prev;
    
    // Constructor to create a new node
    Node(int d) { data = d; }
}

// Define the function to find pairs that add up to 'val'
void findPairs(Node head, int val) {
    Node first = head;
    Node second = head;
    
    // Find the rightmost node
    while (second.next != null)
        second = second.next;
        
    // Create a variable to check if pairs have been found
    boolean pairFound = false;
    
    // Loop through the linked list
    while (first != null && second != null && first != second && second.next != first) {
        // If a pair is found, print it
        if (first.data + second.data == val) {
            System.out.println("(" + first.data + ", " + second.data + ")");
            pairFound = true;
            first = first.next;
            second = second.prev;
        }
        // If the sum of the current pair is too small, move the left pointer
        else if (first.data + second.data < val)
            first = first.next;
        // If the sum of the current pair is too large, move the right pointer
        else
            second = second.prev;
    }
    
    // If no pairs are found, print that there are no pairs
    if (!pairFound)
        System.out.println("No pairs found.");
}


Constructing a Doubly Linked List from a Ternary Tree

We can construct a doubly linked list from a ternary tree by traversing the tree in the following manner:

1. Visit the left subtree recursively.

2. Visit the middle subtree recursively.

3. Visit the right subtree recursively.

Whenever we visit a node, we add it to the end of the linked list using the following steps:

1. If the linked list is empty, the current node becomes the head and tail of the linked list.

2. If the linked list is not empty, we append the current node to the end of the linked list and update the tail to be the current node.

Below is the Python code that implements the above algorithm:

python
class TernaryTreeNode:
    def __init__(self, val=None):
        self.val = val
        self.left = None
        self.mid = None
        self.right = None


class DoublyLinkedNode:
    def __init__(self, val=None):
        self.val = val
        self.prev = None
        self.next = None


class DoublyLinkedList:
    def __init__(self):
        self.head = None
        self.tail = None

    def append(self, node):
        if not self.head:
            self.head = self.tail = node
        else:
            self.tail.next = node
            node.prev = self.tail
            self.tail = node


def ternary_tree_to_doubly_linked_list(node):
    if not node:
        return None

    linked_list = DoublyLinkedList()

    ternary_tree_to_doubly_linked_list(node.left)
    ternary_tree_to_doubly_linked_list(node.mid)
    ternary_tree_to_doubly_linked_list(node.right)

    linked_list.append(DoublyLinkedNode(node.val))

    return linked_list.head

Removing Points from Linked List

Given a linked list of coordinates where neighboring points form either a vertical or horizontal line, we can remove points in between the starting and ending points of the line. This can be done using the following steps:

  1. Traverse the linked list, keeping track of the current point and the previous point.
  2. Check if the current point and the previous point form a horizontal or vertical line with the next point. If they do, continue traversing. If not, remove the points in between the starting and ending points of the line.
  3. Repeat step two until the end of the linked list is reached.

/**
 * Node class for creating linked list
 */
class Node {
  int x, y;
  Node next;

  public Node(int x, int y) {
    this.x = x;
    this.y = y;
    next = null;
  }
}

/**
 * Method for removing points from linked list
 */
void removePoints(Node head) {
  Node curr = head;
  Node prev = null;

  while (curr != null) {
    Node next = curr.next;

    // Check if current point and previous point form horizontal or vertical line with next point
    if (next != null && ((curr.x == prev.x && curr.x == next.x) || (curr.y == prev.y && curr.y == next.y))) {
      prev = curr;
      curr = next;
    } else {
      prev.next = next;
      curr = next;
      }
  }
}


Modifying a Linked List to Move Even Numbers before Odd Numbers

To modify a linked list of integers so that all even numbers appear before all odd numbers, while keeping the even and odd numbers in the same order, we can follow the below approach:

1. Traverse the linked list using a pointer and identify the first odd number node (if any).

2. While traversing the linked list, if an even number node is encountered, move it to the front of the linked list.

3. When we reach the end of the linked list or the first odd number node, return to the beginning of the list and repeat step 1 until we have moved all even number nodes to the front ahead of all odd numbers.

Here's an implementation of the above approach in Python:

python
class Node:
    # class to create node object
    
    def __init__(self, data):
        self.data = data
        self.next = None

def move_evens_to_front(head):
    # function to move all even number nodes to the front of a linked list
    
    # initially, no odd nodes and even nodes present
    odd_start = None
    odd_end = None
    even_start = None
    even_end = None
    
    # traverse the linked list
    while head != None:
        next_node = head.next
        head.next = None
        
        # if the current node is an even number
        if head.data % 2 == 0:
            # add it to the even list
            if even_start == None:
                even_start = head
                even_end = even_start
            else:
                even_end.next = head
                even_end = even_end.next
        
        # if the current node is an odd number
        else:
            # add it to the odd list
            if odd_start == None:
                odd_start = head
                odd_end = odd_start
            else:
                odd_end.next = head
                odd_end = odd_end.next
        
        # move to the next node
        head = next_node
    
    # if even nodes are not present
    if even_start == None:
        return odd_start
    
    # otherwise, add even nodes to the beginning of the odd nodes list
    even_end.next = odd_start
    
    return even_start

We can call this function with the head of our original linked list and it will return a new linked list with even numbers appearing before odd numbers, while preserving the original order of even and odd numbers.

Finding Sum of Last N Nodes in a Linked List

To find the sum of the last N nodes of a linked list, we can follow the below approach:

1. Traverse the linked list and maintain a counter to count the number of nodes in the list. 2. Calculate the difference between the total number of nodes and the given value N. Let's call this difference as K. 3. Traverse the linked list again and stop when we reach the Kth node from the start. 4. Add the values of the nodes from Kth node till the end, which gives us the sum of last N nodes in the linked list.

By following this approach, we can find the sum of last N nodes in a single traversal of the linked list. The time complexity of this approach is O(n), where n is the total number of nodes in the linked list.

Function to sort a linked list based on actual values

Here's an implementation of a function to sort a linked list based on actual values, assuming the input list is already sorted based on absolute values:

Code
#include <stdio.h>
#include <stdlib.h>

// Define the struct for a singly linked list node
struct ListNode {
    int val;
    struct ListNode* next;
};

// Function to insert a new node at the beginning of a linked list
void push(struct ListNode** head_ref, int new_val) {
    struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode));
    new_node->val = new_val;
    new_node->next = *head_ref;
    *head_ref = new_node;
}

// Function to print the contents of a linked list
void printList(struct ListNode* node) {
    while (node != NULL) {
        printf("%d ", node->val);
        node = node->next;
    }
    printf("\n");
}

// Function to sort a linked list based on actual values in O(n) time
struct ListNode* sortList(struct ListNode* head) {
    struct ListNode* curr = head;
    struct ListNode* prev = NULL;
    struct ListNode* temp = NULL;
    int swapped = 0;

    // Bubble sort loop to sort the list
    do {
        swapped = 0;
        curr = head;
        while (curr->next != temp) {
            if (curr->val > curr->next->val) {
                // Swap the nodes
                struct ListNode* tmp = curr->next;
                curr->next = curr->next->next;
                tmp->next = curr;
                if (prev == NULL) {
                    head = prev = tmp;
                } else {
                    prev->next = tmp;
                    prev = tmp;
                }
                swapped = 1;
            } else {
                prev = curr;
                curr = curr->next;
            }
        }
        temp = curr;
    } while (swapped);

    return head;
}

// Driver code to test the function
int main() {
    // Create a linked list: 1 -> -2 -> 3 -> -4 -> -5
    struct ListNode* head = NULL;
    push(&head, -5);
    push(&head, -4);
    push(&head, 3);
    push(&head, -2);
    push(&head, 1);

    printf("Given linked list:\n");
    printList(head);

    head = sortList(head);

    printf("\nLinked list after sorting by actual values:\n");
    printList(head);

    return 0;
}

Explanation: - We start by defining the `ListNode` struct that represents a singly linked list node. - We implement a `push` function to insert a new node at the beginning of the list. - We implement a `printList` function to print the contents of a linked list. - The `sortList` function uses a modified bubble sort algorithm to sort the list based on actual values in O(n) time. - We test the function by creating a linked list and printing the unsorted and sorted versions of the list.

Note: This implementation assumes that the input list contains only integers. If the list contains other data types, the function should be modified accordingly.

Linked List Interview Questions for Experienced: Finding the Length of a Linked List with a Cycle

To find the length of a linked list that contains a cycle, we can use the Floyd's cycle-finding algorithm.

Code:

python
def find_length(head):
    """
    This function finds the length of a linked list with cycle, using Floyd's cycle-finding algorithm.
    :param head: The head node of the linked list.
    :return: The length of the linked list.
    """
    # initializing variables
    slow_ptr = head
    fast_ptr = head
    cycle_found = False
    length = 0

    # traversing through the linked list
    while(slow_ptr and fast_ptr and fast_ptr.next):
        # moving slow_ptr to the next node
        slow_ptr = slow_ptr.next
        # moving fast_ptr to the next to next node
        fast_ptr = fast_ptr.next.next

        # if there exists a cycle in the linked list
        if slow_ptr == fast_ptr:
            cycle_found = True
            break

    # finding the length of the cycle
    if cycle_found:
        cur_ptr = fast_ptr
        while (cur_ptr.next != fast_ptr):
            cur_ptr = cur_ptr.next
            length += 1
        length += 1

    # finding the length of the linked list before the cycle starts
    length_before_cycle = 0
    ptr = head
    while(ptr and ptr != slow_ptr):
        ptr = ptr.next
        length_before_cycle += 1

    # total length of the linked list
    return length_before_cycle + length

In this code, we first initialize two pointers (slow_ptr and fast_ptr) to the head of the linked list and then traverse through the list. Using Floyd's cycle-finding algorithm, we check if there exists a cycle in the linked list. Once we detect the cycle, we find the length of the cycle and the length of the linked list before the cycle starts. Finally, we return the total length of the linked list by adding the length of the cycle and the length of the linked list before the cycle starts.

Adding Polynomial Expressions using Linked Lists

Here is a function that can add two polynomial expressions represented as linked lists. It essentially adds the coefficients that have the same variable powers.


  // Definition of a polynomial term node
  class PolynomialTermNode {
      int coefficient;
      int power;
      PolynomialTermNode next;
  }
  
  // Function to add two polynomial expressions represented by linked lists
  public PolynomialTermNode addPolynomials(PolynomialTermNode poly1, PolynomialTermNode poly2) {
      PolynomialTermNode result = new PolynomialTermNode();
      PolynomialTermNode current = result;
      
      while(poly1 != null && poly2 != null) {
          if(poly1.power == poly2.power) {
              current.coefficient = poly1.coefficient + poly2.coefficient;
              current.power = poly1.power;
              poly1 = poly1.next;
              poly2 = poly2.next;
          } else if(poly1.power > poly2.power) {
              current.coefficient = poly1.coefficient;
              current.power = poly1.power;
              poly1 = poly1.next;
          } else {
              current.coefficient = poly2.coefficient;
              current.power = poly2.power;
              poly2 = poly2.next;
          }
          if(poly1 != null || poly2 != null) {
              current.next = new PolynomialTermNode();
              current = current.next;
          }
      }
      
      // Handling the remaining polynomial terms in case one list is longer than the other
      while(poly1 != null) {
          current.coefficient = poly1.coefficient;
          current.power = poly1.power;
          poly1 = poly1.next;
          if(poly1 != null) {
              current.next = new PolynomialTermNode();
              current = current.next;
          }
      }
      
      while(poly2 != null) {
          current.coefficient = poly2.coefficient;
          current.power = poly2.power;
          poly2 = poly2.next;
          if(poly2 != null) {
              current.next = new PolynomialTermNode();
              current = current.next;
          }
      }
      
      return result;
  }


Finding the Merging Point of Two Lists with Varying Lengths in Python

Given two lists with varying lengths, we need to find the point at which they merge. One way to do this is by using two pointers.

Code:


def get_merge_point(list1, list2):
    current1 = list1.head # Pointer for list1
    current2 = list2.head # Pointer for list2

    # Traverse the two lists
    while current1 != current2:

        # If the end of List 1 is reached, switch to List 2
        if current1 is None:
            current1 = list2.head
        else:
            current1 = current1.next

        # If the end of List 2 is reached, switch to List 1
        if current2 is None:
            current2 = list1.head
        else:
            current2 = current2.next

    # Return the merging point
    return current1.data

In this code, we start by initializing two pointers - one for each list. We then traverse the two lists simultaneously, moving the pointers one node at a time.

If a pointer reaches the end of its list, we switch it to the head of the other list. This way, the pointers are always tracing the longer list until they reach the point where the two lists merge.

Once the pointers meet at this merging point, we return the data of that node.

Counting Triplets in a Sorted Doubly Linked List

Given a value X and a sorted doubly linked list of different nodes where no two nodes have the same data. The task is to count the number of triplets in the list that add up to X. The expected time complexity is O(N^2) and the expected space complexity is O(1).


// Node class to create a node of linked list
class Node {
    int data;
    Node prev, next;
    Node(int val) {
        data = val;
        prev = next = null;
    }
}

// Function to count triplets that sum to X 
static int countTriplets(Node head, int X) {
    Node i, j, k;
    int count = 0;
    // Initialize pointers i and j
    for (i = head; i != null; i = i.next) {
        for (j = i.next; j != null; j = j.next) {
            // Initialize k as the largest node 
            // among the nodes next to j 
            k = j.next;

            // Traverse the remaining nodes
            // to find the triplets
            while (k != null) {
                if ((i.data + j.data + k.data) == X) {
                    count++;
                }
                k = k.next;
            }
        }
    }
    // Return the count of triplets
    return count;
}

Explanation:

We use three pointers i, j, and k to traverse the list and find triplets which sum up to X. We initialize i and j at the first two nodes of the list and traverse till we find the last node of the list. To ensure that k is the largest node among the nodes next to j, we initialize it to the next node of j and traverse till the last node of the list. We then check if the sum of i, j, and k is equal to X. If true, we increment the count. Finally, we return the count of triplets.

Finding Length of Longest Palindrome Linked List

Given a linked list, this program finds the length of the longest palindrome list that appears in the given linked list using O(1) extra space.


class Node {
    int data;
    Node next;
    
    Node(int d) {
        data = d;
        next = null;
    }
}

public class PalindromeLinkedList {
    public static int getLengthOfLongestPalindrome(Node head) {
        int maxLength = 0;
        
        // Check each possible center of palindrome
        for (Node curr = head; curr != null; curr = curr.next) {
            int length = 0;
            Node even = curr;
            Node odd = curr.next;
            
            // Check for even length palindrome
            while (even != null && even.next != null && even.data == even.next.data) {
                length += 2;
                even = even.next.next;
            }
            
            // Check for odd length palindrome
            while (odd != null && odd.next != null && curr.data == odd.next.data) {
                length += 2;
                odd = odd.next.next;
            }
            
            // If longest palindrome seen until now is smaller 
            // than the current palindrome, update maxLength
            if (maxLength < length + 1) {
                maxLength = length + 1;
            }
        }
        
        return maxLength;
    }
    
    public static void main(String[] args) {
        // Sample input linked list
        Node head = new Node(2);
        head.next = new Node(4);
        head.next.next = new Node(3);
        head.next.next.next = new Node(4);
        head.next.next.next.next = new Node(2);
        
        int lengthOfLongestPalindrome = getLengthOfLongestPalindrome(head);
        System.out.println("Length of longest palindrome in the given linked list is " + lengthOfLongestPalindrome);
    }
}


Algorithm to Update "Arbitrary" Pointer in Singly Linked List

To update the "arbitrary" pointer in a singly linked list to point to the next node with a greater value, the following algorithm can be implemented:

1. Traverse the linked list from the beginning to end. 2. For each node, compare its value with the values of all following nodes. 3. If a node with a greater value is found, update the "arbitrary" pointer of the current node to point to that node. 4. If no node with a greater value is found, leave the "arbitrary" pointer of the current node as null. 5. Continue traversal until the end of the linked list is reached.

This algorithm ensures that each node's "arbitrary" pointer points to the next node with a greater value, if one exists. If there are multiple nodes with the same greatest value, the "arbitrary" pointer will point to the first occurrence of that value. If no node with a greater value is found, the "arbitrary" pointer will remain null.

Creating a Doubly Linked List with One Address Field

In a standard doubly linked list, two address fields are used to store the addresses of the previous and the next nodes. However, using a XOR linked list, we can create a doubly linked list with only one space for the address field in every node.

Here's an example implementation:


struct Node {
   int data;
   Node* xor_ptr; // Pointer which stores XOR of one previous and one next nodes
};

Node* XOR(Node *a, Node *b) { // Returns XOR of two nodes
    return reinterpret_cast<Node *> (reinterpret_cast<uintptr_t> (a) ^ reinterpret_cast<uintptr_t> (b));
}

class DoublyLinkedList {
    Node *head;

public:
    DoublyLinkedList() {
        head = NULL;
    }

    void insert_end(int data) {
        Node *new_node = new Node;
        new_node->data = data;

        // If list is empty, simply make new node as head
        if (head == NULL) {
            new_node->xor_ptr = XOR(NULL, NULL);
            head = new_node;
        }
        else {
            Node *prev = NULL;
            Node *curr = head;
            Node *next = XOR(prev, curr->xor_ptr);

            while (next != NULL) { // traverse to the end of the list
                prev = curr;
                curr = next;
                next = XOR(prev, curr->xor_ptr);
            }

            // add new node at the end of the list
            new_node->xor_ptr = XOR(curr, NULL);
            curr->xor_ptr = XOR(prev, new_node);
        }
    }

    void print_list() const { // print the list in forward direction
        Node *prev = NULL;
        Node *curr = head;
        Node *next;
        cout << "Doubly linked list (in forward direction): ";

        while (curr) {
            cout << curr->data << " ";
            next = XOR(prev, curr->xor_ptr);
            prev = curr;
            curr = next;
        }
        cout << endl;
    }
};

The XOR function takes two node pointers as input and returns the XOR of their addresses. We use this function to calculate the XOR of the previous and the next nodes while traversing the list.

In the insert_end function, we create a new node and add it at the end of the list. If the list is empty, we simply make the new node the head of the list. Otherwise, we traverse the list from the head till the end, and add the new node at the end.

The print_list function is used to print the list in the forward direction (since we can't traverse the list backwards using XOR pointers alone).

By using XOR pointers, we are able to create a doubly linked list with only one space for the address field in every node.

Flattening and Sorting a Linked List of Linked Lists

To flatten and sort a linked list of linked lists, we can follow the following approach:

1. Traverse the linked list and for each node, merge its linked list with the current result linked list. 2. Keep merging until we reach the end of the linked list. 3. Sort the final merged linked list using any sorting algorithm (e.g. merge sort, quick sort, etc.).

We can implement this approach as follows:


// Definition for a linked list node
class LinkedListNode {
    int val;
    LinkedListNode next;
    LinkedListNode down;
    LinkedListNode(int val) {
        this.val = val;
        this.next = null;
        this.down = null;
    }
}

// Function to merge two linked lists
private LinkedListNode mergeLinkedLists(LinkedListNode l1, LinkedListNode l2) {
    if (l1 == null) {
        return l2;
    }
    if (l2 == null) {
        return l1;
    }
    // Pick the smaller value and recur
    if (l1.val < l2.val) {
        l1.down = mergeLinkedLists(l1.down, l2);
        return l1;
    }
    else {
        l2.down = mergeLinkedLists(l1, l2.down);
        return l2;
    }
}

// Function to flatten the linked list and sort it
public LinkedListNode flattenAndSortLinkedList(LinkedListNode head) {
    if (head == null || head.next == null) {
        return head;
    }
    // Recursively flatten and sort the linked list
    head.next = flattenAndSortLinkedList(head.next);
    head = mergeLinkedLists(head, head.next);
    return head;
}

In the above code, we first define a `LinkedListNode` class to represent each node of the linked list. We also define a helper function `mergeLinkedLists` to merge two linked lists recursively.

Then we define the main function `flattenAndSortLinkedList` which takes the head of the linked list as input. We first check if the `head` node is null or if it is the last node in the linked list. If true, we return the node itself.

Otherwise, we recursively flatten and sort the linked list by calling the `flattenAndSortLinkedList` function on the next node of the `head` node. We then merge the `head` node and the next node using the `mergeLinkedLists` function. Finally, we return the `head` node after merging.

With this approach, we can efficiently flatten and sort a linked list of linked lists.

Technical Interview Guides

Here are guides for technical interviews, categorized from introductory to advanced levels.

View All

Best MCQ

As part of their written examination, numerous tech companies necessitate candidates to complete multiple-choice questions (MCQs) assessing their technical aptitude.

View MCQ's
Made with love
This website uses cookies to make IQCode work for you. By using this site, you agree to our cookie policy

Welcome Back!

Sign up to unlock all of IQCode features:
  • Test your skills and track progress
  • Engage in comprehensive interactive courses
  • Commit to daily skill-enhancing challenges
  • Solve practical, real-world issues
  • Share your insights and learnings
Create an account
Sign in
Recover lost password
Or log in with

Create a Free Account

Sign up to unlock all of IQCode features:
  • Test your skills and track progress
  • Engage in comprehensive interactive courses
  • Commit to daily skill-enhancing challenges
  • Solve practical, real-world issues
  • Share your insights and learnings
Create an account
Sign up
Or sign up with
By signing up, you agree to the Terms and Conditions and Privacy Policy. You also agree to receive product-related marketing emails from IQCode, which you can unsubscribe from at any time.