Zuo Chengyun - linked list

Posted by delhiris on Sun, 02 Jan 2022 13:21:32 +0100

hash and ordered table

unordered_set usage
unordered_map usage (the same as the map usage, but the map is orderly, which is out of order) -- algorithm note 6.4

Ordered tables are Set and Map

No matter how many records are put in the hash table, the time is complex, and love is a constant level.

Linked list

Reverse linked list

Note: the adjustment of the linked list may have the operation of changing the header, so it will bring the return value. If the header is not changed, it can be defined as void type.

In fact, this problem is similar to the following figure. In external sorting, use two pointers to point to the two linked lists. Who is smaller and who moves to the right. When equal, put value into a new array and move together. One of them crossed the line and stopped.


Written test: just put it directly in the stack

The stack comes in first and then out. After putting it in, it pops out upside down. It's different from the original linked list.

More space saving: put the right part of the linked list on the stack, and then pop it up. Compare it with the original linked list from the beginning.
This method uses the fast and slow pointer (an important skill) to find the midpoint.

Fast and slow pointer: the fast pointer takes two steps at A time, and the slow pointer takes one step at A time. When the fast pointer is finished, the slow pointer comes to the midpoint. Then, when traversing down the midpoint, reverse the order, point to the empty midpoint, and point back to the rest. As shown in the figure below, A and B go to the middle at the same time, compare each step, and stop when one goes to the empty. Finally, restore the right part of the linked list to normal, and then return true/false.

The speed pointer needs to be customized: boundary conditions

//Stack code only

  struct ListNode {
 	int val;
 	struct ListNode *next;
  };
 
class Solution {
public:
   
    bool isPail(ListNode* head) {
        // write code here
    stack<int> st;
	ListNode* cur = head;
	while(cur != NULL)
	{
		st.push(cur->val);
		cur = cur->next;
	}

	while(head != NULL)
	{
		if(head->val != st.top()){
            
			return false;
	}	
        st.pop();
	head = head->next;
	}
        return true;
    }
};
//n/2
// need n/2 extra space
	public static boolean isPalindrome2(Node head) {
		if (head == null || head.next == null) {
			return true;
		}
		Node right = head.next;
		Node cur = head;
		while (cur.next != null && cur.next.next != null) {
			right = right.next;
			cur = cur.next.next;
		}
		Stack<Node> stack = new Stack<Node>();
		while (right != null) {
			stack.push(right);
			right = right.next;
		}
		while (!stack.isEmpty()) {
			if (head.value != stack.pop().value) {
				return false;
			}
			head = head.next;
		}
		return true;
	}

//Speed pointer

// need O(1) extra space
	public static boolean isPalindrome3(Node head) {
		if (head == null || head.next == null) {
			return true;
		}
		Node n1 = head;
		Node n2 = head;
		while (n2.next != null && n2.next.next != null) { // find mid node
			n1 = n1.next; // n1 -> mid
			n2 = n2.next.next; // n2 -> end
		}
		n2 = n1.next; // n2 -> right part first node
		n1.next = null; // mid.next -> null
		Node n3 = null;
		while (n2 != null) { // right part convert
			n3 = n2.next; // n3 -> save next node
			n2.next = n1; // next of right node convert
			n1 = n2; // n1 move
			n2 = n3; // n2 move
		}
		n3 = n1; // n3 -> save last node
		n2 = head;// n2 -> left first node
		boolean res = true;
		while (n1 != null && n2 != null) { // check palindrome
			if (n1.value != n2.value) {
				res = false;
				break;
			}
			n1 = n1.next; // left to mid
			n2 = n2.next; // right to mid
		}
		n1 = n3.next;
		n3.next = null;
		while (n1 != null) { // recover list
			n2 = n1.next;
			n1.next = n3;
			n3 = n1;
			n1 = n2;
		}
		return res;
	}

Title: a group of numbers. Sort them. Those less than a certain number are on the left and those greater than a certain number are on the right.

Set 6 parameters
SH

Finally, when connecting, pay attention to the discussion boundary. For example, if there is no number less than 5, an error will be reported if the null pointer points to a number equal to 5

public static Node listPartition2(Node head, int pivot) {
		Node sH = null; // small head
		Node sT = null; // small tail
		Node eH = null; // equal head
		Node eT = null; // equal tail
		Node bH = null; // big head
		Node bT = null; // big tail
		Node next = null; // save next node
		// every node distributed to three lists
		while (head != null) {
			next = head.next;
			head.next = null;
			if (head.value < pivot) {
				if (sH == null) {//If it is the first node
					sH = head;//Set the head and tail less than the area
					sT = head;
				} else {//Not the first node
					sT.next = head;//Connect the next pointer of the old tail to the current node
					sT = head;//The current node becomes the new tail of the old region
				}
			} else if (head.value == pivot) {
				if (eH == null) {
					eH = head;
					eT = head;
				} else {
					eT.next = head;
					eT = head;
				}
			} else {
				if (bH == null) {
					bH = head;
					bT = head;
				} else {
					bT.next = head;
					bT = head;
				}
			}
			head = next;
		}
		// small and equal reconnect
		if (sT != null) {
			sT.next = eH;
			eT = eT == null ? sT : eT;
		}
		// all reconnect
		if (eT != null) {
			eT.next = bH;
		}
		return sH != null ? sH : eH != null ? eH : bH;
	}

//With extra space, the hash table is solved

Prepare a hash table, map
key is the Node type, indicating the old Node. value is also the Node type, indicating the cloned new Node corresponding to the old Node

Without considering how to connect the new linked list, copy each old linked list to the new linked list, and then put it in the map,

The second step is to set the pointer in the next and random directions of the new linked list, and traverse the hash table or the old linked list to set the pointer

After traversing 1, the clone node is 1 ', and its next is 2' (because 1next is 2). Similarly, random is set to 3 '. Last return 1 '

public static Node copyListWithRand1(Node head) {
		HashMap<Node, Node> map = new HashMap<Node, Node>();
		Node cur = head;
		//The first while generates a clone node from the map
		while (cur != null) {
			map.put(cur, new Node(cur.value));
			cur = cur.next;
		}
		
		cur = head;
		//Traverse the old linked list again
		while (cur != null) {
		//map.get(cur) = cur ', i.e. clone node
			map.get(cur).next = map.get(cur.next);
			//Here is the random pointer
			map.get(cur).rand = map.get(cur.rand);
			cur = cur.next;
		}
		//The clone node corresponding to the old man is the head of the new head
		return map.get(head);
	}

Link problem in linked list

Function: a linked list goes down. If there is a ring, it returns the first node into the ring, and if there is no ring, it returns null.

The circle in the figure below is the ring in node

Method 1: use the hash table and set, as shown in the following figure, to traverse the linked list. The first node that appears twice is the ring entry node.

//It is difficult to use fast and slow pointers without additional data structures

PS: if a single linked list has a ring, it will fall into its own ring and can't get out, because there is only one next pointer
The following figure shows the fast and slow pointer. Remember the conclusion: the slow pointer takes one step at a time and the fast pointer takes two steps at a time. If it comes to the end, it means there is no ring.
If the fast and slow pointers meet for the first time at the end (they must meet on the ring), the fast pointer will also take one step at a time and jump to the beginning. If they meet again, they must be at the entrance of the ring.

If a node of two linked lists intersects, the subsequent parts of this node are common, as shown in the following figure. According to this conclusion, the following figure compares whether the last node addresses of the two linked lists are equal. If they are not equal, they must not intersect. If equal, start looking for the first intersection node.

For example, the length of linked list 1 is 100 and the length of linked list 2 is 80. First, let linked list 1 take 20 steps, and then linked lists 1 and 2 move forward together. Compare the nodes, and they will surely go to the first common intersection node.


Intersect and disjoint, two cases

public static Node noLoop(Node head1, Node head2) {
		if (head1 == null || head2 == null) {
			return null;
		}
		Node cur1 = head1;
		Node cur2 = head2;
		int n = 0;
		while (cur1.next != null) {
			n++;
			cur1 = cur1.next;
		}
		while (cur2.next != null) {
			n--;
			cur2 = cur2.next;
		}
		if (cur1 != cur2) {
			return null;
		}
		//n is the length of linked list 1 minus linked list 2,
		cur1 = n > 0 ? head1 : head2;//Who grows, whose head becomes curl1
		cur2 = cur1 == head1 ? head2 : head1;//Who is short, whose head becomes curl2
		n = Math.abs(n);
		while (n != 0) {
			n--;
			cur1 = cur1.next;
		}
		while (cur1 != cur2) {
			cur1 = cur1.next;
			cur2 = cur2.next;
		}
		return cur1;
	}

PS: a linked list has rings and a linked list has no rings, so it is impossible to intersect