FastPrepThread-Safe Concurrent Linked List

Thread-Safe Concurrent Linked List

Apple logoApple● MediumFULLTIMEONSITE INTERVIEW

Problem statement

Implement a singly linked list of integers that many threads can use at the same time. It starts empty and supports insert, delete, and read. Positions start at 0, and repeated values are separate nodes.

For this exercise, the calls arrive as two lists. operations[i] names a call and args[i] holds its arguments. The lists show one legal order of the concurrent calls, so each call must see the complete list left by the call before it, with no partial change showing.

  • "INSERT" with [index, value]: add value so that it sits at position index, and return 1. Values at that position and later move back by one. An index equal to the current size adds to the end. If index is greater than the size, return -1 and change nothing.
  • "DELETE" with [index]: remove the node at position index and return its value. If no node is there, return -1 and change nothing.
  • "READ" with [index]: return the value at position index and leave the list as it is. If no node is there, return -1.

Return an array with one result for each operation, in order.

The interview focused on making these calls safe under real concurrency. Try hand-over-hand locking: take the next node's lock before you release the current one, and keep a sentinel node before the first position. The judge runs your code on one thread, so it checks the results of each call and cannot check your locks or how well they scale.

Function

runConcurrentLinkedList(operations: String[], args: int[][]) → int[]

Examples

Example 1

operations = ["INSERT","INSERT","INSERT","READ","DELETE","READ"]args = [[0,10],[1,30],[1,20],[1],[0],[0]]return = [1,1,1,20,10,20]

Three inserts build the list. The third insert puts 20 at position 1, so the list is [10, 20, 30]. READ at position 1 returns 20. DELETE at position 0 returns 10 and leaves [20, 30], so the last READ at position 0 returns 20.

Example 2

operations = ["READ","DELETE","INSERT","INSERT","READ"]args = [[0],[0],[1,5],[0,5],[0]]return = [-1,-1,-1,1,5]

The list is empty, so READ and DELETE at position 0 both return -1. INSERT at index 1 also returns -1, because the size is 0. INSERT at index 0 works, and READ at position 0 then returns 5.

Example 3

operations = ["INSERT","INSERT","INSERT","DELETE","READ","READ","READ"]args = [[0,7],[0,7],[2,0],[1],[0],[1],[2]]return = [1,1,1,7,7,0,-1]

The inserts build [7, 7, 0]. The two 7 values are separate nodes. DELETE at position 1 returns 7 and leaves [7, 0]. READ at position 0 returns 7, and READ at position 1 returns the stored 0. Position 2 is now empty, so its READ returns -1.

Constraints

  • 1 <= operations.length <= 500
  • args.length == operations.length
  • operations[i] is "INSERT", "DELETE", or "READ".
  • args[i] is [index, value] for "INSERT" and [index] for "DELETE" and "READ".
  • 0 <= index <= 500
  • 0 <= value <= 10^9

More Apple problems

See Apple hiring insights
Saved
public int[] runConcurrentLinkedList(String[] operations, int[][] args) {
    // Write your code here.
}
Checking account…