{"id":22814361,"url":"https://github.com/devinterview-io/data-structures-interview-questions","last_synced_at":"2026-02-02T06:02:39.147Z","repository":{"id":108757584,"uuid":"327223591","full_name":"Devinterview-io/data-structures-interview-questions","owner":"Devinterview-io","description":"🟣 Data Structures interview questions and answers to help you prepare for your next data structures and algorithms interview in 2025.","archived":false,"fork":false,"pushed_at":"2025-05-19T16:59:14.000Z","size":29,"stargazers_count":49,"open_issues_count":0,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-23T16:09:55.637Z","etag":null,"topics":["algorithms","algorithms-and-data-structures","algorithms-and-data-structures-interview-questions","algorithms-interview-questions","coding-interview-questions","data-structures","data-structures-and-algorithms","data-structures-and-algorithms-interview-questions","data-structures-interview-questions","data-structures-questions","data-structures-tech-interview","software-developer-interview","software-engineer-interview"],"latest_commit_sha":null,"homepage":"https://devinterview.io/","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Devinterview-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-01-06T06:39:50.000Z","updated_at":"2025-05-19T16:59:17.000Z","dependencies_parsed_at":"2025-05-19T18:08:49.408Z","dependency_job_id":null,"html_url":"https://github.com/Devinterview-io/data-structures-interview-questions","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Devinterview-io/data-structures-interview-questions","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Devinterview-io%2Fdata-structures-interview-questions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Devinterview-io%2Fdata-structures-interview-questions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Devinterview-io%2Fdata-structures-interview-questions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Devinterview-io%2Fdata-structures-interview-questions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Devinterview-io","download_url":"https://codeload.github.com/Devinterview-io/data-structures-interview-questions/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Devinterview-io%2Fdata-structures-interview-questions/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29006677,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-02T04:25:24.522Z","status":"ssl_error","status_checked_at":"2026-02-02T04:24:51.069Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algorithms","algorithms-and-data-structures","algorithms-and-data-structures-interview-questions","algorithms-interview-questions","coding-interview-questions","data-structures","data-structures-and-algorithms","data-structures-and-algorithms-interview-questions","data-structures-interview-questions","data-structures-questions","data-structures-tech-interview","software-developer-interview","software-engineer-interview"],"created_at":"2024-12-12T13:08:21.780Z","updated_at":"2026-02-02T06:02:39.138Z","avatar_url":"https://github.com/Devinterview-io.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Top 100 Data Structures Interview Questions in 2026\n\n\u003cdiv\u003e\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://devinterview.io/questions/data-structures-and-algorithms/\"\u003e\n\u003cimg src=\"https://firebasestorage.googleapis.com/v0/b/dev-stack-app.appspot.com/o/github-blog-img%2Fdata-structures-and-algorithms-github-img.jpg?alt=media\u0026token=fa19cf0c-ed41-4954-ae0d-d4533b071bc6\" alt=\"data-structures-and-algorithms\" width=\"100%\"\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\n#### You can also find all 100 answers here 👉 [Devinterview.io - Data Structures](https://devinterview.io/questions/data-structures-and-algorithms/data-structures-interview-questions)\n\n\u003cbr\u003e\n\n## 1. Explain how you would reverse an array in place.\n\n**In-place reversal** modifies the original array without extra space.\n\nHere is a general-purpose implementation:\n\n### Code Example: Array Reversal\n\nHere is the Python code:\n\n```python\ndef reverse_array(arr):\n    start, end = 0, len(arr) - 1\n    while start \u003c end:\n        arr[start], arr[end] = arr[end], arr[start]\n        start, end = start + 1, end - 1\n        \nmy_array = [1, 2, 3, 4, 5]\nprint(\"Original Array:\", my_array)\nreverse_array(my_array)\nprint(\"Reversed Array:\", my_array)\n```\n\u003cbr\u003e\n\n## 2. What is the difference between an _array_ and a _linked list_?\n\nLet me put the two fundamental type of lists,  **Arrays** and **Linked Lists**, into perspective.\n\n### Key Distinctions\n\n#### Data Organization\n\n* **Array**: Employs sequential memory storage and each element has a unique index.\n* **Linked List**: Elements are scattered in memory and accessed sequentially via references (pointers).\n\n#### Memory Management\n\n* **Array**: Typically requires a single, contiguous memory block.\n* **Linked List**: Memory allocations are dynamic and non-contiguous.\n\n#### Complexity Analysis\n\n| Operation     | Array     | Linked List |\n| ------------- |-----------| ------------|\n| Access        | $O(1)$ (with index)  | $O(n)$ |\n| Bulk Insertion| $O(n)$ or $O(1)$  | $O(1)$ |\n| Deletion      | $O(n)$ to $O(1)$   | $O(1)$ |\n\n### When to Use Each\n\n- **Arrays** are preferable when:\n  - There's a need for direct or random access such as in lookup tables.\n  - The data will remain relatively unchanged, and performance in accessing elements takes precedence over frequent insertions or deletions.\n\n- **Linked Lists** are more suitable when:\n  - Frequent insertions and deletions are expected, especially in the middle.\n  - The exact size of the list isn't known in advance, and you want the memory to be used flexibly.\n  - The primary operations are sequential, such as iteration from the beginning to the end.\n\n### Code Example: Array vs. Linked List\n\nHere is the Python code:\n\n#### Array\n```python\n# Define array\nmy_array = [10, 20, 30, 40, 50]\n\n# Access element by index\nprint(my_array[2])  # Output: 30\n\n# Bulk insertion at the beginning\nmy_array = [5, 6, 7] + my_array\nprint(my_array)  # Output: [5, 6, 7, 10, 20, 30, 40, 50]\n\n# Deletion from the middle\ndel my_array[4]\nprint(my_array)  # Output: [5, 6, 7, 10, 30, 40, 50]\n```\n\n#### Linked List\n```python\n# Define linked list nodes (in reality, you'd have a LinkedList class)\nclass Node:\n    def __init__(self, data):\n        self.data = data\n        self.next = None\n\n# Create linked list\nhead = Node(10)\nnode1 = Node(20)\nnode2 = Node(30)\nhead.next = node1\nnode1.next = node2\n\n# Bulk insertion at the beginning\nnew_node1 = Node(5)\nnew_node2 = Node(6)\nnew_node3 = Node(7)\nnew_node3.next = head\nhead = new_node1\nnew_node1.next = new_node2\nprint_nodes(head)  # Output: 5, 6, 7, 10, 20, 30\n\n# Deletion from the middle\nnew_node1.next = new_node3\n# Now, just print_nodes(head) will output: 5, 6, 7, 20, 30\n```\n\u003cbr\u003e\n\n## 3. How would you check for duplicates in an array without using extra space?\n\n**Checking for duplicates** in an array without additional space is a common challenge with solutions using hash functions, sorting, and mathematical calculations.\n\n### Brute Force Method\n\nThe code checks for duplicates based on numerical repetition.\n\n#### Complexity Analysis\n\n- **Time Complexity**: $O(n^2)$\n- **Space Complexity**: $O(1)$\n\n#### Code Implementation\n\nHere is the Python code:\n\n```python\ndef has_duplicates(arr):\n    n = len(arr)\n    for i in range(n):\n        for j in range(i+1, n):\n            if arr[i] == arr[j]:\n                return True\n    return False\n\narr = [1, 2, 3, 4, 3]\nprint(has_duplicates(arr))  # Output: True\n```\n\n### Sorting Approach\n\nThis method involves sorting the array using a **comparison-based sorting algorithm** like Quick Sort. If two adjacent elements are the same, then the array has duplicates.\n\n#### Complexity Analysis\n\n- **Time Complexity**: Best/Worst: $O(n \\log n)$\n- **Space Complexity**: $O(1)$ or $O(n)$ depending on sorting algorithm\n\n#### Code Implementation\n\nHere is the Python code:\n\n```python\ndef has_duplicates_sorted(arr):\n    arr.sort()\n    n = len(arr)\n    for i in range(n - 1):\n        if arr[i] == arr[i+1]:\n            return True\n    return False\n\narr = [1, 2, 3, 4, 3]\nprint(has_duplicates_sorted(arr))  # Output: True\n```\n\n### Mathematical Approach\n\nFor this method, **the sum of numbers in the array** is calculated. Mathematically, if no duplicates are present, the sum of consecutive natural numbers can be calculated to compare against the actual sum.\n\nIf $\\text{actual sum} - \\text{sum of numbers in the array} = 0$, there are no duplicates.\n\n#### Code Implementation\n\nHere is the Python code:\n\n```python\ndef has_duplicates_math(arr):\n    array_sum = sum(arr)\n    n = len(arr)\n    expected_sum = (n * (n-1)) // 2  # Sum of first (n-1) natural numbers\n    return array_sum - expected_sum != 0\n\narr = [1, 2, 3, 4, 5, 5]\nprint(has_duplicates_math(arr))  # Output: True\n```\n\u003cbr\u003e\n\n## 4. Can you explain how to perform a _binary search_ on a sorted array?\n\nLet's look at the high-level **strategy** behind binary search and then walk through a **step-by-step example**.\n\n### Binary Search Strategy\n\n1. **Divide \u0026 Conquer**: Begin with the entire sorted array and refine the search range in each step.\n2. **Comparison**: Use the middle element to determine the next search range.\n3. **Repetition**: Continue dividing the array until the target is found or the search range is empty.\n\n### Step-by-Step Example\n\nLet's consider the following array with the target value of `17`:\n\n```plaintext\n[1, 3, 6, 7, 9, 12, 15, 17, 20, 21]\n```\n\n1. **Initial Pointers**: We start with the whole array.  \n   ```plaintext\n   [1, 3, 6, 7, 9, 12, 15, 17, 20, 21]  \n   ^                               ^\n   Low                             High\n   Middle: (Low + High) / 2 = 5\n   ```\n\n   This identifies the `Middle` number as `12`.\n\n2. **Comparison**: Since the `Middle` number is less than the target `17`, we can **discard** the left portion of the array.\n   ```plaintext\n   [15, 17, 20, 21]\n   ^           ^\n   Low        High\n   ```\n\n3. **Updated Pointers**: We now have a reduced array to search.\n   ```plaintext\n   Middle = 7\n   ^      ^\n   Low   High\n   ```\n\n4. **Final Comparison**:  \n   Since the `Middle` number is now the target, `17`, the search is successfully concluded.\n\u003cbr\u003e\n\n## 5. How would you rotate a two-dimensional _array_ by 90 degrees?\n\nRotating a 2D array by $90^\\circ$ can be visually understood as a **transpose** followed by a **reversal** of rows or columns.\n\n### Algorithm: Transpose and Reverse\n\n1. **Transpose**: Swap each element $A[i][j]$ with its counterpart $A[j][i]$\n2. **Reverse Rows (for $90^\\circ$ CW)** or Columns (for $90^\\circ$ CCW)\n\n### Complexity Analysis\n\n- **Time Complexity**: Both steps run in $O(n^2)$ time.\n- **Space Complexity**: Since we do an in-place rotation, it's $O(1)$.\n\n#### Code Example: Matrix Rotation\n\nHere is the Python code:\n\n```python\ndef rotate_2d_clockwise(matrix):\n    n = len(matrix)\n    # Transpose\n    for i in range(n):\n        for j in range(i, n):\n            matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]\n    # Reverse Rows\n    for i in range(n):\n        for j in range(n//2):\n            matrix[i][j], matrix[i][n-j-1] = matrix[i][n-j-1], matrix[i][j]\n\n    return matrix\n\ndef rotate_matrix_ccw(matrix):\n    n = len(matrix)\n    # Transpose\n    for i in range(n):\n        for j in range(i, n):\n            matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]\n    # Reverse Columns\n    for i in range(n):\n        for j in range(n//2):\n            matrix[j][i], matrix[n-j-1][i] = matrix[n-j-1][i], matrix[j][i]\n\n    return matrix\n\n# Test \nmatrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]\nprint(rotate_2d_clockwise(matrix))\n# Output: [[7, 4, 1], [8, 5, 2], [9, 6, 3]]\n```\n\u003cbr\u003e\n\n## 6. Describe an algorithm to compress a string such as \"_aabbccc_\" to \"_a2b2c3_\".\n\nYou can compress a string following the count of each character. For example, \"_aabbccc_\" becomes \"_a2b2c3_\".\n\nThe python code for this algorithm is:\n\n```python\ndef compress_string(input_string):\n    # Initialize\n    current_char = input_string[0]\n    char_count = 1\n    output = current_char\n\n    # Iterate through the string\n    for char in input_string[1:]:\n        # If the character matches the current one, increment count\n        if char == current_char:\n            char_count += 1\n        else:  # Append the count to the output and reset for the new character\n            output += str(char_count) + char\n            current_char = char\n            char_count = 1\n\n    # Append the last character's count\n    output += str(char_count)\n\n    # If the compressed string is shorter than the original string, return it\n    return output if len(output) \u003c len(input_string) else input_string\n```\n\n### Time Complexity\n\nThis algorithm has a time complexity of $O(n)$ since it processes each character of the input string exactly once.\n\n### Space Complexity\n\nThe space complexity is $O(k)$, where $k$ is the length of the compressed string. This is because the **output** string is stored in memory.\n\u003cbr\u003e\n\n## 7. What is an _array slice_ and how is it implemented in programming languages?\n\nLet's look at what is an **Array Slice** and how it's implemented in some programming languages.\n\n### What is an Array Slice?\n\nAn array slice is a view on an existing array that acts as a smaller array. The slice references a continuous section of the original array which allows for efficient data access and manipulation.\n\nArray slices are commonly used in languages like **Python**, **Rust**, and **Go**.\n\n### Key Operations\n\n- **Read**: Access elements in the slice.\n- **Write**: Modify elements within the slice.\n- **Grow/Shrink**: Resize the slice, often DWARF amortized.\n- **Iteration**: Iterate over the elements in the slice.\n\n### Underlying Mechanism\n\nA slice typically contains:\n\n1. A **pointer** to the start of the slice.\n2. The **length** of the slice (the number of elements in the slice).\n3. The **capacity** of the slice (the maximum number of elements that the slice can hold).\n\n#### Benefit of Use\n\n- **No Copy Overhead**: Slices don't duplicate the underlying data; they're just references. This makes them efficient and memory-friendly.\n- **Flexibility**: Slices can adapt as the array changes in size.\n- **Safety**: Languages like **Rust** use slices for enforcing safety measures, preventing out-of-bounds access and memory issues.\n\n### Popular Implementations\n\n- **Python**: Uses list slicing, with syntax like `my_list[2:5]`. This creates a new list.\n  \n- **Go Lang**: Employs slices extensively and is perhaps the most slice-oriented language out there.\n\n- **Rust**: Similar to Go, it's a language heavily focused on memory safety, and slices are fundamental in that regard.\n\n### Code Example: Array Slicing\n\nHere is the **Python** code:\n\n  ```python\n  original_list = [1, 2, 3, 4, 5]\n  my_slice = original_list[1:4]  # Creates a new list: [2, 3, 4]\n  ```\n  \n  Here is the **Rust** code:\n\n  ```rust\n  let original_vec = vec![1, 2, 3, 4, 5];\n  let my_slice = \u0026original_vec[1..4];  // References a slice: [2, 3, 4]\n  ```\n\n  And here is the **Go** code:\n\n  ```go\n  originalArray := [5]int{1, 2, 3, 4, 5}\n  mySlice := originalArray[1:4]  // References the originalArray from index 1 to 3\n  ```\n\u003cbr\u003e\n\n## 8. Can you discuss the _time complexity_ of _array insertion_ and _deletion_?\n\nBoth **array insertions** and **deletions** have a time complexity of $O(n)$ due to potential need for data re-arrangement.\n\n### Array Insertion\n\n- **Beginning**: $O(n)$ if array full; $1$ for shifting.\n- **Middle**: $O(n)$ to make room and insert.\n- **End**: $O(1)$ on average for appending.\n\n### Array Deletion\n\n- **Beginning**: $O(n)$ due to re-arrangement often needed.\n- **Middle**: $O(n)$ as it involves shifting.\n- **End**: $O(1)$ for most cases, but $O(n)$ when dynamic resizing is required.\n\u003cbr\u003e\n\n## 9. What are some ways to merge two sorted _arrays_ into one sorted _array_?\n\nMerging two sorted arrays into a new sorted array can be accomplished through a variety of well-established techniques.\n\n### Methods of Merging Sorted Arrays\n\n1. **Using Additional Space**: \n    - Create a new array and add elements from both arrays using two pointers, then return the merged list.\n    - Time Complexity: $O(n + m)$ - where $n$ and $m$ are the number of elements in each array. This approach is simple and intuitive.\n\n2. **Using a Min Heap**:\n   - Select the smallest element from both arrays using a min-heap and insert it into the new array.\n   - Time Complexity: $O((n + m) \\log (n + m))$ \n   - Space Complexity: $O(n + m)$ - Heap might contain all the elements.\n   - This approach is useful when the arrays are too large to fit in memory.\n\n3. **In-Place Merge**:\n    - Implement a merge similar to the one used in **Merge Sort**, directly within the input array.\n    - Time Complexity: $O(n \\cdot m)$ - where $n$ and $m$ are the number of elements in each array.\n    - **In-Place Merging** becomes inefficient as the number of insertions increases.\n\n4. **Using Binary Search**: \n   - Keep dividing the larger array into two parts and using binary search to find the correct position for elements in the smaller array.\n   - Time Complexity: $O(m \\log n)$\n\n5. **Two-Pointer Technique**:\n   - Initialize two pointers, one for each array, and compare them to determine the next element in the merged array.\n   - Time Complexity: $O(n + m)$\n\u003cbr\u003e\n\n## 10. How do you find the _kth largest element_ in an unsorted _array_?\n\nTo find the $k^{\\text{th}}$ largest element in an unsorted array, you can **leverage heaps or quicksort**.\n\n### Quickselect Algorithm\n\n- **Idea**: Partition the array using a pivot (similar to quicksort) and divide into subarrays until the partitioning index is the $k^{\\text{th}}$ largest element.\n\n- **Time Complexity**: \n  - Worst-case: $O(n^2)$ - This occurs when we're faced with the least optimized scenario, reducing $n$ by only one element for each stitch step.\n  - Average-case: $O(n)$ - Average performance is fast, making the expected time complexity linear.\n  \n- **Code Example**: Python\n\n  ```python\n  import random\n  \n  def quickselect(arr, k):\n      if arr:\n          pivot = random.choice(arr)\n          left = [x for x in arr if x \u003c pivot]\n          right = [x for x in arr if x \u003e pivot]\n          equal = [x for x in arr if x == pivot]\n          if k \u003c len(left):\n              return quickselect(left, k)\n          elif k \u003c len(left) + len(equal):\n              return pivot\n          else:\n              return quickselect(right, k - len(left) - len(equal))\n  ```\n\n### Heap Method\n\n- Build a **max-heap** $O(n)$ - This takes linear time, making $O(n) + O(k \\log n) = O(n + k \\log n)$.\n- Extract the max element $k$ times (each time re-heapifying the remaining elements).\n\n### Code Example: Python \n\n```python\nimport heapq\n\ndef kth_largest_heap(arr, k):\n    if k \u003e len(arr): return None\n    neg_nums = [-i for i in arr]\n    heapq.heapify(neg_nums)\n    k_largest = [heapq.heappop(neg_nums) for _ in range(k)]\n    return -k_largest[-1]\n```\n\u003cbr\u003e\n\n## 11. Explain how a _singly linked list_ differs from a _doubly linked list_.\n\n**Singly linked lists** and **doubly linked lists** differ in how they manage node-to-node relationships.\n\n### Structure\n\n- **Singly Linked List**: Each node points to the next node.\n\n- **Doubly Linked List**: Both previous and next nodes are pointed to.\n\n### Visual Representation\n\n#### Singly Linked List\n\n![Singly Linked List](https://firebasestorage.googleapis.com/v0/b/dev-stack-app.appspot.com/o/linked-lists%2Fsingly-linked-list.svg?alt=media\u0026token=c6e2ad4f-e2d4-4977-a215-6253e71b6040)\n\n#### Doubly Linked List\n\n![Doubly Linked List](https://firebasestorage.googleapis.com/v0/b/dev-stack-app.appspot.com/o/linked-lists%2Fdoubly-linked-list.svg?alt=media\u0026token=5e14dad3-c42a-43aa-99ff-940ab1d9cc3d)\n\n### Key Distinctions\n\n- **Access Direction**: Singly linked lists facilitate one-way traversal, while doubly linked lists support bi-directional traversal.\n\n- **Head and Tail Movements**: Singly linked lists only operate on the head, while doubly linked lists can manipulate the head and tail.\n\n- **Backward Traversal Efficiency**: Due to their structure, singly linked lists may be less efficient for backward traversal.\n\n- **Memory Requirement**: Doubly linked lists use more memory as each node carries an extra pointer.\n\n### Code Example: Singly Linked List\n\nHere is the Java code:\n\n```java\npublic class SinglyLinkedList {\n    \n    private static class Node {\n        private int data;\n        private Node next;\n\n        public Node(int data) {\n            this.data = data;\n            this.next = null;\n        }\n    }\n\n    private Node head;\n\n    public void insertFirst(int data) {\n        Node newNode = new Node(data);\n        newNode.next = head;\n        head = newNode;\n    }\n\n    public void display() {\n        Node current = head;\n        while (current != null) {\n            System.out.println(current.data);\n            current = current.next;\n        }\n    }\n}\n```\n\n### Code Example: Doubly Linked List\n\nHere is the Java code:\n\n```java\npublic class DoublyLinkedList {\n    \n    private static class Node {\n        private int data;\n        private Node previous;\n        private Node next;\n\n        public Node(int data) {\n            this.data = data;\n            this.previous = null;\n            this.next = null;\n        }\n    }\n\n    private Node head;\n    private Node tail;\n\n    public void insertFirst(int data) {\n        Node newNode = new Node(data);\n        if (head == null) {\n            head = newNode;\n            tail = newNode;\n        } else {\n            head.previous = newNode;\n            newNode.next = head;\n            head = newNode;\n        }\n    }\n\n    public void display() {\n        Node current = head;\n        while (current != null) {\n            System.out.println(current.data);\n            current = current.next;\n        }\n    }\n\n    public void displayBackward() {\n        Node current = tail;\n        while (current != null) {\n            System.out.println(current.data);\n            current = current.previous;\n        }\n    }\n}\n```\n\u003cbr\u003e\n\n## 12. How would you detect a _cycle_ in a _linked list_?\n\n**Cycle detection** in a linked list is a fundamental algorithm that uses pointers to identify if a linked list has a repeating sequence.\n\n### Floyd's \"Tortoise and Hare\" Algorithm\n\nFloyd's algorithm utilizes two pointers:\n\n- The \"tortoise\" moves one step each iteration.\n- The \"hare\" moves two steps.\n\nIf the linked list does not have a cycle, the hare either reaches the end (or null) before the tortoise, or vice versa. However, if there is a cycle, the two pointers **are guaranteed to meet** inside the cycle.\n\n### Algorithm Steps\n\n1. Initialize both pointers to the start of the linked list.\n2. Move the tortoise one step and the hare two steps.\n3. Continuously advance the pointers in their respective steps:\n   - If the tortoise reaches the hare (a collision point), return such a point.\n   - If either pointer reaches the end (null), conclude there is no cycle.\n\n### Visual Representation\n\n![Floyd's Algorithm](https://firebasestorage.googleapis.com/v0/b/dev-stack-app.appspot.com/o/data%20structures%2Ffloyd-warshall-algorithm.png?alt=media\u0026token=edbf8bd3-979a-44e8-ad49-041e9f30cece)\n\n### Complexity Analysis\n\n- **Time Complexity**: $O(n)$ where $n$ is the number of nodes in the linked list, due to each pointer visiting each node only once.\n- **Space Complexity**: $O(1)$ as the algorithm uses only a constant amount of extra space.\n\n### Code Example: Floyd's Cycle Detection\n\nHere is the Python code:\n\n```python\ndef has_cycle(head):\n    tortoise = head\n    hare = head\n\n    while hare and hare.next:\n        tortoise = tortoise.next\n        hare = hare.next.next\n\n        if tortoise == hare:\n            return True\n\n    return False\n```\n\u003cbr\u003e\n\n## 13. What are the major operations you can perform on a _linked list_, and their _time complexities_?\n\nLet's look at the major operations you can perform on a **singly linked list** and their associated time complexities:\n\n### Operations \u0026 Time Complexities\n\n#### Access (Read/Write) $O(n)$\n\n- **Head**: Constant time: $O(1)$.\n- **Tail**: $O(n)$ without a tail pointer, but constant with a tail pointer.\n- **Middle or k-th Element**: $\\frac{n}{2}$ is around the middle node; getting k-th element requires $O(k)$.\n\n#### Search $O(n)$\n\n- **Unordered**: May require scanning the entire list. Worst case: $O(n)$.\n- **Ordered**: You can stop as soon as the value exceeds what you're looking for.\n\n#### Insertion $O(1)$ without tail pointer, $O(n)$ with tail pointer\n\n- **Head**: $O(1)$\n- **Tail**: $O(1)$ with a tail pointer, otherwise $O(n)$.\n- **Middle**: $O(1)$ with tail pointer and finding position in $O(1)$ time; otherwise, it's $O(n)$.\n\n#### Deletion $O(1)$ for Head and Tail, $O(n)$ otherwise\n\n- **Head**: $O(1)$\n- **Tail**: $O(n)$ because you must find the node before the tail for pointer reversal with a single pass.\n- **Middle**: $O(n)$ since you need to find the node before the one to be deleted.\n\n#### Length $O(n)$\n\n- **Naive**: Requires a full traversal. Every addition or removal requires this traversal.\n- **Keep Count**: Maintain a separate counter, updating it with each addition or removal.\n\n### Code Example: Singly Linked List Basic Operations\n\nHere is the Python code:\n\n```python\nclass Node:\n    def __init__(self, data):\n        self.data = data\n        self.next = None\n\nclass SinglyLinkedList:\n    def __init__(self):\n        self.head = None\n    \n    def append(self, data):  # O(n) without tail pointer\n        new_node = Node(data)\n        if not self.head:\n            self.head = new_node\n            return\n        last_node = self.head\n        while last_node.next:\n            last_node = last_node.next\n        last_node.next = new_node\n    \n    def delete(self, data):  # O(n) only if element is not at head\n        current_node = self.head\n        if current_node.data == data:\n            self.head = current_node.next\n            current_node = None\n            return\n        while current_node:\n            if current_node.data == data:\n                break\n            prev = current_node\n            current_node = current_node.next\n        if current_node is None:\n            return\n        prev.next = current_node.next\n        current_node = None\n\n    def get_middle(self):  # O(n)\n        slow, fast = self.head, self.head\n        while fast and fast.next:\n            slow = slow.next\n            fast = fast.next.next\n        return slow\n\n    def get_kth(self, k):  # O(k)\n        current_node, count = self.head, 0\n        while current_node:\n            count += 1\n            if count == k:\n                return current_node\n            current_node = current_node.next\n        return None\n\n    # Other methods: display, length, etc.\n```\n\u003cbr\u003e\n\n## 14. Can you describe an _in-place algorithm_ to reverse a _linked list_?\n\n**In-Place Algorithms** modify data structures with a constant amount of extra working space $O(1)$.\n\nA **Singly Linked List** presents a straightforward example of an in-place data structure, well-suited for in-place reversal algorithms.\n\n### Reversing a Linked List: Core Concept\n\nThe reversal algorithm just needs to update each node's `next` reference so that they point to the previous node. A few key steps achieve this:\n\n1. **Initialize**: Keep track of the three key nodes: `previous`, `current`, and `next`.\n2. **Reverse Links**: Update each node to instead point to the previous one in line.\n3. **Move Pointers**: Shift `previous`, `current`, and `next` nodes by one position for the next iteration. \n\nThis process proceeds iteratively until `current` reaches the end, i.e., `NULL`.\n\n### Complexity Analysis\n\n- **Time Complexity**: The algorithm exhibits a linear time complexity of $O(n)$ as it visits each node once.\n- **Space Complexity**: As the algorithm operates in-place, only a constant amount of extra space (for nodes pointers) is required: $O(1)$.\n\n### Code Example: In-Place List Reversal\n\nHere is the Python code:\n\n```python\nclass Node:\n    def __init__(self, data=None):\n        self.data = data\n        self.next = None\n\nclass LinkedList:\n    def __init__(self):\n        self.head = None\n\n    def append(self, data):\n        new_node = Node(data)\n        if not self.head:\n            self.head = new_node\n            return\n        last_node = self.head\n        while last_node.next:\n            last_node = last_node.next\n        last_node.next = new_node\n\n    def reverse_inplace(self):\n        previous = None\n        current = self.head\n        while current:\n            next_node = current.next\n            current.next = previous\n            previous = current\n            current = next_node\n        self.head = previous\n\n    def display(self):\n        elements = []\n        current = self.head\n        while current:\n            elements.append(current.data)\n            current = current.next\n        print(\" -\u003e \".join(str(data) for data in elements))\n\n# Populate the linked list\nllist = LinkedList()\nvalues = [4, 2, 8, 3, 1, 9]\nfor value in values:\n    llist.append(value)\n\n# Display original\nprint(\"Original Linked List:\")\nllist.display()\n\n# Reverse in-place and display\nllist.reverse_inplace()\nprint(\"\\nAfter Reversal:\")\nllist.display()\n```\n\u003cbr\u003e\n\n## 15. Explain how you would find the _middle element_ of a _linked list_ in one pass.\n\n**Finding the middle element** of a linked list is a common problem with several efficient approaches, such as the **two-pointer (or \"runner\") technique**.\n\n### Two-Pointer Technique\n\n#### Explanation\n\nThe two-pointer technique uses two pointers, often named `slow` and `fast`, to traverse the list. While `fast` moves two positions at a time, `slow` trails behind, covering a single position per move. When `fast` reaches the end, `slow` will be standing on the middle element.\n\n### Example\n\nGiven the linked list: 1 -\u003e 2 -\u003e 3 -\u003e 4 -\u003e 5 -\u003e 6 -\u003e 7\n\nThe pointers will traverse as follows:\n\n- (1) `slow`: 1; `fast`: 2\n- (2) `slow`: 2; `fast`: 4\n- (3) `slow`: 3; `fast`: 6\n- (4) `slow`: 4; `fast`: end\n\nAt (4), the `slow` pointer has reached the middle point.\n\n### Complexity Analysis\n\n- **Time Complexity**: $O(N)$ -- For every N nodes, we check each node once.\n- **Space Complexity**: $O(1)$ -- We only use pointers; no extra data structures are involved.\n\n### Code Example: Two-Pointer (Runner) technique\n\nHere is the Python implementation:\n\n```python\ndef find_middle_node(head):\n    if not head:\n        return None\n\n    slow = fast = head\n    while fast and fast.next:\n        slow = slow.next\n        fast = fast.next.next\n    return slow\n```\n\u003cbr\u003e\n\n\n\n#### Explore all 100 answers here 👉 [Devinterview.io - Data Structures](https://devinterview.io/questions/data-structures-and-algorithms/data-structures-interview-questions)\n\n\u003cbr\u003e\n\n\u003ca href=\"https://devinterview.io/questions/data-structures-and-algorithms/\"\u003e\n\u003cimg src=\"https://firebasestorage.googleapis.com/v0/b/dev-stack-app.appspot.com/o/github-blog-img%2Fdata-structures-and-algorithms-github-img.jpg?alt=media\u0026token=fa19cf0c-ed41-4954-ae0d-d4533b071bc6\" alt=\"data-structures-and-algorithms\" width=\"100%\"\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevinterview-io%2Fdata-structures-interview-questions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevinterview-io%2Fdata-structures-interview-questions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevinterview-io%2Fdata-structures-interview-questions/lists"}