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
  • 21. Palindrome Linked List
  • 22. Palindrome Partitioning
  • 23. Palindrome Number
  • 24. Next Greater Node In Linked List
  • 25. Split Linked List in Parts
  1. Leetcode
  2. LinkedList

Palindrome

During an interview, it's important to understand the problem requirements and constraints. This problem requires understanding linked lists and how to reverse nodes in groups. It's also critical to explain the approach you will use to solve the problem and justify its correctness and efficiency. Additionally, explaining the code and using clear variable names, as demonstrated in the optimized Java code, can help your interviewer follow your thought process.

21. Palindrome Linked List

  1. Problem Description: The problem link for "Palindrome Linked List" on LeetCode is: https://leetcode.com/problems/palindrome-linked-list/

Given a singly linked list, determine if it is a palindrome.

  1. Java Code:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isPalindrome(ListNode head) {
        if (head == null || head.next == null) {
            // An empty list or a list with only one node is considered a palindrome.
            return true;
        }
        
        // Find the middle of the linked list using the two-pointer technique.
        ListNode slow = head;
        ListNode fast = head;
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        
        // Reverse the second half of the linked list.
        ListNode reversedSecondHalf = reverse(slow.next);
        
        // Compare the first half and the reversed second half of the linked list.
        ListNode curr1 = head;
        ListNode curr2 = reversedSecondHalf;
        while (curr2 != null) {
            if (curr1.val != curr2.val) {
                return false;
            }
            curr1 = curr1.next;
            curr2 = curr2.next;
        }
        
        return true;
    }
    
    private ListNode reverse(ListNode head) {
        ListNode prev = null;
        ListNode curr = head;
        while (curr != null) {
            ListNode next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }
}
  1. Algorithm & Approach:

  • To solve this problem, we can use the two-pointer technique along with reversing the second half of the linked list. This approach allows us to compare the first half with the reversed second half to determine if the linked list is a palindrome.

  • We start by checking for some base cases. An empty list or a list with only one node is considered a palindrome.

  • Next, we find the middle of the linked list using the two-pointer technique. We use a slow pointer and a fast pointer. The slow pointer moves one node at a time while the fast pointer moves two nodes at a time. By the time the fast pointer reaches the end of the list, the slow pointer will be at the middle.

  • After finding the middle, we reverse the second half of the linked list. To reverse the linked list, we maintain three pointers: prev (for the previous node), curr (for the current node), and next (for the next node). We update the pointers accordingly and reverse the pointers.

  • Once we have the reversed second half, we compare the first half with the reversed second half. We iterate through both halves simultaneously, comparing the values at each node. If at any point the values differ, we know that the linked list is not a palindrome and return false.

  • If we successfully complete the comparison without any differences, we conclude that the linked list is a palindrome and return true.

During an interview, it is important to explain the approach clearly and step through the code to demonstrate understanding. Additionally, consider discussing test cases, time complexity, and space complexity for the solution.

22. Palindrome Partitioning

Sure, I can help with that. Here's the problem description for "Palindrome Partitioning" on LeetCode:

Problem Description: Given a string s, partition s such that every substring of the partition is a palindrome. Return all possible palindrome partitioning of s.

Example: Input: "aab" Output: [["a","a","b"],["aa","b"]]

Here's the link to the problem on LeetCode: https://leetcode.com/problems/palindrome-partitioning/

And here's the optimized Java code for the problem "Palindrome Partitioning" with detailed comments:

import java.util.ArrayList;
import java.util.List;

class Solution {
    public List<List<String>> partition(String s) {
        List<List<String>> result = new ArrayList<>();
        List<String> current = new ArrayList<>();
        backtrack(result, current, s, 0);
        return result;
    }

    private void backtrack(List<List<String>> result, List<String> current, String s, int start) {
        // If we have checked the entire string, add the current partition to the result
        if (start == s.length()) {
            result.add(new ArrayList<>(current));
            return;
        }

        // Iterate over each substring starting from the 'start' index
        for (int i = start; i < s.length(); i++) {
            // Check if the current substring is a palindrome
            if (isPalindrome(s, start, i)) {
                // If it is a palindrome, add it to the current partition
                current.add(s.substring(start, i + 1));
                // Recursively partition the remaining string
                backtrack(result, current, s, i + 1);
                // Remove the current substring from the current partition for backtracking
                current.remove(current.size() - 1);
            }
        }
    }

    private boolean isPalindrome(String s, int left, int right) {
        // Check if the substring is a palindrome
        while (left < right) {
            if (s.charAt(left) != s.charAt(right)) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

Algorithm & Approach: The problem can be solved using backtracking, which is a standard technique for exploring all possible solutions. The idea is to divide the string 's' into all possible substrings and check if each substring is a palindrome. If it is, then add it to the current partition and recursively partition the remaining string. The backtracking part involves removing the last added substring from the current partition to explore different possibilities.

During an interview process, you can follow these steps to think through the problem:

  1. Understand the problem requirements and constraints.

  2. Identify the possible patterns or techniques that can be applied to solve the problem. In this case, backtracking is a suitable technique.

  3. Break down the problem into smaller subproblems and think about the algorithm's overall structure.

  4. Consider the base cases and termination conditions of the recursion.

  5. Implement the code step by step, ensuring to add necessary checks and optimizations.

  6. Test the code against given examples and custom test cases to validate its correctness.

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

23. Palindrome Number

  1. Problem Description: The problem is to determine whether a given integer is a palindrome or not. A palindrome is a number that reads the same backward as forward.

LeetCode Problem Link: https://leetcode.com/problems/palindrome-number/

  1. Optimized Java Solution:

public class PalindromeNumber {
    public boolean isPalindrome(int x) {
        if (x < 0 || (x != 0 && x % 10 == 0)) {
            return false;
        }
        
        int reversed = 0;
        while (x > reversed) {
            reversed = reversed * 10 + x % 10;
            x /= 10;
        }
        
        return x == reversed || x == reversed / 10;
    }
}
  1. Problem Solving Approach:

To solve this problem efficiently, you can follow the following steps:

  • If the number is negative or ends with a zero but is not zero itself, it cannot be a palindrome. So, in such cases, we can return false directly.

  • To reverse the number, we can iteratively extract the last digit of the number and add it to a new reversed number by multiplying the reversed number by 10 and then adding the last digit. Meanwhile, we divide the original number by 10 to remove the last digit.

  • We iterate until the original number is greater than the reversed number, as reversing half of the number is sufficient. At each iteration, we update the reversed number and divide the original number by 10.

  • After the iteration, we check if the reversed number is equal to the original number (in case of an odd-length palindrome) or the reversed number divided by 10 (in case of an even-length palindrome). If either of these conditions is true, the number is a palindrome and we return true. Otherwise, it is not a palindrome and we return false.

This approach has a time complexity of O(log N) and a space complexity of O(1).

During interviews, it's crucial to communicate the thought process and discuss the optimized solution. Explain the reasoning behind each step and clarify any doubts of the interviewer. Remember to consider edge cases and handle input validation appropriately.

24. Next Greater Node In Linked List

  1. Problem Description and Link: The problem "Next Greater Node In Linked List" asks us to take a linked list of non-negative integers and, for each node, find the value of the next greater node in the list. If there is no such next greater node, we should set the value as 0. We need to return an array of these "next greater node" values. Link to the problem on LeetCode: https://leetcode.com/problems/next-greater-node-in-linked-list/

  2. Optimized Java Code with Detailed Comments: Here is the optimized Java code to solve the "Next Greater Node In Linked List" problem on LeetCode:

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public class Solution {
    public int[] nextLargerNodes(ListNode head) {
        // Step 1: Traverse the linked list to find its length
        int length = 0;
        ListNode current = head;
        while (current != null) {
            length++;
            current = current.next;
        }
        
        // Step 2: Initialize the result array and stack
        int[] result = new int[length];
        int[] stack = new int[length];
        int top = -1;
        current = head;
        int index = 0;
        
        // Step 3: Traverse the linked list again to find the next greater nodes
        while (current != null) {
            // If the stack is not empty and the value at the current node is greater than the value at the stack's top
            while (top >= 0 && current.val > current[stack[top]]) {
                // Set the value at the index stored in the stack as the next greater node for the current node
                result[stack[top]] = current.val;
                top--;
            }
            
            // Push the index of the current node into the stack
            stack[++top] = index;
            // Move to the next node
            current = current.next;
            index++;
        }
        
        // Step 4: Set the next greater nodes for the remaining nodes in the stack as 0 
        while (top >= 0) {
            result[stack[top]] = 0;
            top--;
        }
        
        return result;
    }
}
  1. Algorithm and Thinking Process: When approaching this problem during an interview, you can follow these steps:

  • Step 1: Traverse the linked list to find its length. This will be useful for initializing the result array and stack.

  • Step 2: Initialize the result array and stack. The result array will store the next greater node values for each node in the linked list, and the stack will store the indices of the nodes for which we have not yet found the next greater node.

  • Step 3: Traverse the linked list again to find the next greater nodes. For each node, compare its value with the value at the top of the stack. If the value at the current node is greater, set the value at the index stored in the stack as the next greater node for the current node. Repeat this process until the value at the current node is not greater than the value at the top of the stack. After that, push the index of the current node into the stack. Continue this process until you reach the end of the linked list.

  • Step 4: Set the next greater nodes for the remaining nodes in the stack as 0, as there is no greater node available for them.

In terms of the algorithm's time complexity, we traverse the linked list twice, which takes O(N) time, where N is the length of the linked list. Since we are using a stack to store the indices, the space complexity is also O(N) in the worst case.

Make sure to mention and explain these steps and the time/space complexity analysis during your interview to demonstrate your understanding of the problem and your ability to think through it.

25. Split Linked List in Parts

  1. Problem Description:

The problem "Split Linked List in Parts" on LeetCode asks us to split a given linked list into k parts such that each part has a size as even as possible. If there are remaining nodes after dividing equally, the extra nodes should be distributed among the first few parts.

Link to the problem: https://leetcode.com/problems/split-linked-list-in-parts/

  1. Optimized Java Code:

Here is the optimized Java code for the problem "Split Linked List in Parts" with detailed comments:

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

class Solution {
    public ListNode[] splitListToParts(ListNode head, int k) {
        // Step 1: Find the length of the linked list
        int length = 0;
        ListNode current = head;
        while (current != null) {
            length++;
            current = current.next;
        }
        
        // Step 2: Calculate the size of each part and the number of extra nodes
        int partSize = length / k;
        int extraNodes = length % k;
        
        // Step 3: Create an array to store the resulting parts
        ListNode[] result = new ListNode[k];
        
        // Step 4: Split the linked list into parts
        current = head;
        for (int i = 0; i < k && current != null; i++) {
            result[i] = current; // Store the starting node of each part
            
            // Calculate the size of the current part
            int size = partSize;
            if (extraNodes > 0) {
                size++;
                extraNodes--;
            }
            
            // Move current to the end of the current part
            for (int j = 1; j < size; j++) {
                current = current.next;
            }
            
            // Break the link between the current part and the next part
            ListNode next = current.next;
            current.next = null;
            current = next;
        }
        
        return result;
    }
}
  1. Detailed Description:

The algorithm for solving this problem can be broken down into the following steps:

  1. Find the length of the given linked list by traversing through all the nodes. This will help us determine the size of each part.

  2. Calculate the size of each part by dividing the length of the linked list by k. Also, calculate the number of extra nodes remaining after dividing equally.

  3. Create an array of ListNode to store the resulting parts. The size of the array is k.

  4. Start splitting the linked list into parts. Iterate k times and for each iteration, do the following:

    • Store the starting node of the current part in the array.

    • Calculate the size of the current part. If there are extra nodes remaining, add one more node to the current part's size.

    • Move the current pointer to the last node of the current part by traversing size - 1 nodes.

    • Break the link between the current part and the next part by setting the next pointer of the current node to null.

    • Move the current pointer to the next node (the starting node of the next part) for the next iteration.

This algorithm ensures that the linked list is split into k parts with each part having a size as even as possible. If there are remaining nodes, they are distributed among the first few parts to keep the size difference minimum.

PreviousPartitioning and MergingNextMiscellaneous

Last updated 1 year ago