LeetCode 138 copies linked lists with random pointers

Keywords: Algorithm leetcode linked list

Title Description:

Give you a linked list with a length of n. each node contains an additional random pointer random, which can point to any node or empty node in the linked list.

To construct this linked list   Deep copy.   The deep copy should consist of exactly n new nodes, in which the value of each new node is set to the value of its corresponding original node. The next pointer and random pointer of the new node should also point to the new node in the replication linked list, and these pointers in the original linked list and the replication linked list can represent the same linked list state. The pointer in the copy linked list should not point to the node in the original linked list.

For example, if there are two nodes X and Y in the original linked list, where x.random → y. Then the corresponding two nodes X and Y in the copy linked list also have x.random →   y .

Returns the header node of the copy linked list.

With a   n   A linked list of nodes to represent the linked list in input / output. One per node   [val, random_index]   express:

  • Val: an indication   Node.val   Integer of.
  • random_index: the node index pointed by the random pointer (range from   0   reach   n - 1); If it does not point to any node; otherwise   null  .

Your code only accepts the head node of the original linked list as the incoming parameter.

Example:

Input: head = [[7, null], [13, 0], [11, 4], [10, 2], [1, 0]]

Output: [[7, null], [13, 0], [11, 4], [10, 2], [1, 0]]

Input: head = [[1, 1], [2, 1]]

Output: [[1, 1], [2, 1]]

Input: head = [[3, null], [3, 0], [3, null]]

Output: [[3, null], [3, 0], [3, null]]

Input: head = []

Output: []

Personal solution:

Traverse the original linked list, create new nodes according to the value of each node, store them in the ArrayList, and then traverse the ArrayList to connect each node

Write a method to calculate the position of the specified node in the linked list. It is relatively simple. You only need to traverse from the node until you find the target node and return to index

Again, traverse the original linked list, calculate the index value corresponding to the random node of each node, and set the random point of each node in the ArrayList according to the index value

The idea is simple, but the traversal times are too many, resulting in too much time complexity

public Node copyRandomList(Node head) {
	if (head == null) {
		return null;
	}
	Node cur = head;
	ArrayList<Node> nodeList = new ArrayList<>();
	while (cur != null) {
		nodeList.add(new Node(cur.val));
		cur = cur.next;
	}
	for (int i = 0; i < nodeList.size() - 1; i++) {
		nodeList.get(i).next = nodeList.get(i + 1);
	}
	cur = head;
	int index;
	for (Node node : nodeList) {
		if (cur.random == null) {
			node.random = null;
		} else {
			index = getIndex(head, cur.random);
			node.random = nodeList.get(index);
		}
		cur = cur.next;
	}
	return nodeList.get(0);
}

public int getIndex(Node head, Node random) {
	Node cur = head;
	int distance = 0;
	while (cur != null) {
		if (cur == random) {
			return distance;
		}
		cur = cur.next;
		distance++;
	}
	return -1;
}

Official solution 1 (backtracking + hash table):

The following is reproduced from LeetCode

Backtracking is used to make the copy operations of each node independent of each other. For the current node, we first copy, and then we copy the successor node of the current node and the node pointed by the random pointer of the current node. After the copy is completed, we return the pointer of the created new node to complete the assignment of the two pointers of the current node.

Record the creation of a new node corresponding to each node with a hash table. In the process of traversing the linked list, check   Successor node of the current node   And the creation of the node pointed to by the random pointer of the current node. If the new node of any of these two nodes is not created, we will create it recursively immediately. When we copy and trace back to the current layer, we can complete the pointer assignment of the current node. Note that a node may be pointed to by multiple other nodes, so we may try to copy a node recursively many times. In order to prevent repeated copying, we need to first check whether the current node has been copied. If it has been copied, we can directly take the pointer of the copied node from the hash table and return it.

class Solution {
    Map<Node, Node> cachedNode = new HashMap<Node, Node>();

    public Node copyRandomList(Node head) {
        if (head == null) {
            return null;
        }
        if (!cachedNode.containsKey(head)) {
            Node headNew = new Node(head.val);
            cachedNode.put(head, headNew);
            headNew.next = copyRandomList(head.next);
            headNew.random = copyRandomList(head.random);
        }
        return cachedNode.get(head);
    }
}

Official solution 2 (iteration + node splitting):

The following is reproduced from LeetCode

Split each node in the linked list into two connected nodes, for example, for linked list A   → B → C, we can split it into A → A '→ B → B' → C → C '. For any original node S, its copy node S' is its successor node.

In this way, we can directly find each copy node S'   The node to which the random pointer of should point is the node T to which the random pointer of its original node S points   Successor node T '  . Note that the random pointer of the original node may be null. We need to judge this situation in particular.

When we complete the assignment of the random pointer of the copy node, we only need to split the linked list according to the types of the original node and the copy node, and we only need to traverse it once. Similarly, it should be noted that the successor node of the last copy node is empty. We need to judge this situation in particular.

public Node copyRandomList2(Node head) {
	if (head == null) {
		return null;
	}
	for (Node node = head; node != null; node = node.next.next) {
		Node nodeNew = new Node(node.val);
		nodeNew.next = node.next;
		node.next = nodeNew;
	}
	for (Node node = head; node != null; node = node.next.next) {
		Node nodeNew = node.next;
		nodeNew.random = (node.random != null) ? node.random.next : null;
	}
	Node headNew = head.next;
	for (Node node = head; node != null; node = node.next) {
		Node nodeNew = node.next;
		node.next = node.next.next;
		nodeNew.next = (nodeNew.next != null) ? nodeNew.next.next : null;
	}
	return headNew;
}

Posted by Zaid on Mon, 13 Sep 2021 21:05:07 -0700