Zuoshen algorithm notes - linked list

Keywords: less

Palindrome linked list

  1. Create a stack, store all the data in the linked list in the stack, and then compare the data in the stack with all the data in the linked list.
  2. Using the single step pointer and the double step pointer, when the two-step pointer finally reaches the end of the list, the second half of the list point is reversed, and then the data size is compared from the head of the chain and the end of the list at the same time to realize the judgment of the palindrome list. The spatial complexity is O (1).
public static class Node{
	public int value ;
	public Node next;
	public Node(int data){
		this.value = data;
	}
}

//Need n extra space
public static boolean isPalinddrome1(Node head){
	Stack<Node> stack = new Stack<Node>();//Build a node type stack
	Node cur = head;
	while(cur!=null){
		stack.push(cur);
		cur = cur.next;
	}
	while(head!= null){
		if(head.value != stack.pop().value){
			return false
		}
		head = head.next;
	}
	return true;
}


//n/2 extra space required
public static boolean isPalindrome2(Node node){
	//When only 0 or 1 numbers are included, the palindrome structure must be satisfied
	if(head == null ||head.next == null){
		return true;
	}
	//Set right to single step traversal and cur to double step traversal. Therefore, it is necessary to exclude the linked list containing only 0, 1 data in advance, otherwise it cannot be judged.
	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 ture;
}

//O(1) extra space required
public static boolean isPalindrome3(Node head){
	if(head == null|| head.next == null){
		return ture;
	}
	Node n1 = head;
	Node n2 = head;
	while(n2.next !=null&&n2.next.next != null){
		n1 = n1.next;
		n2 = n2.next.next;
	}
	//n2 becomes the first point in the right half, separating the left and right sides
	n2 = n1.next;
	n1.next = null;
	Node n3 = null;
	//Reverse the link list of the right half through the while loop
	while(n2! = null){
		n3 = n2.next;
		n2.next = n1;
		n1 = n2;
		n2 = n3;
	}
	n3 = n1;//n3 represents the last node
	n2 = head;//n2 is the first node on the left
	boolean res = true;
	while(n1 != null && n2 != null){
		if(n1.value != n2.value){
			return false;
		}
		n1 = n1.next;
		n2 = n2.next;
	}
	//Finally, restore the entire list
	n1 = n3.next;
	n3.next = null;
	while(n1 != null){
		n2 = n1.next;
		n1.next = n3;
		n3 = n1;
		n1 = n2;
	}
	return res;
}
	

One way list is divided into small on the left, equal in the middle and large on the right according to a certain value

  1. Dutch flag problem, prepare an extra array. The Dutch flag issue is not stable.
  2. Set three nodes, which are less than MEM, equal to mem and greater than mem. Each node is set with two variables, head and end. Each time the value is increased, end + + will be stored in the linked list.
public static class Node{
	public int value;
	public Node next;
	public Node(int data){
		this.value = data;
	}
}

public static Node listPartition1(Node head,int pivot){
	if(head == null){
		return head;
	}
	Node cur = head;
	int i = 0;
	//It is responsible for calculating the length of the whole linked list, so as to know how long the new array is
	while(cur !=null){
		i++;
		cur = cur.next;
	}
	//New array
	Node[] nodeArr = new Node[i];
	i = 0;
	cur = head;
	//Put the data in the linked list into the array
	for(i = 0;i!= nodeArr.length;i++){
		nodeArr[i] = cur;
		cur = cur.next;
	}
	//Using the Dutch flag problem for sorting, the Dutch flag was mentioned in the previous explanation of quick sorting. If you don't understand it, you can turn it forward.
	arrPartition(nodeArr,pivot);
	//Change the array to the form of linked list to return
	for(i = 1;i != nodeArr.length;i++){
		nodeArr[i-1].next =nodeArr[i];
	}
	nodeArr[i-1].next = null;
	return nodeArr[0];
}
//The data in the whole Node array is exchanged
public static void arrpartition(Node[] nodeArr,int pivot){
	int small = -1;
	int big = nodeArr.length;
	int index = 0;
	while(index != big){
		if(nodeArr[index].value<pivot){
			swap(nodeArr,++small,index++);
		}else if(nodeArr[index].value>pivot){
			swap(nodeArr,--big,index);
		}else{
			index++;
		}
	}
}
public static void swap(Node[] nodeArr,int a,int b){
	Node tmp = nodeArr[a];
	nodeArr[a] = nodeArr[b];
	nodeArr[b] = tmp;
}

public static Node listPartition2(Node head ,int pivot){
	Node sH = null;//H for head, T for Tail, s for small, e for equal, and b for big.
	Node sT = null;
	Node eH = null;
	Node eT = null;
	Node bH = null;
	Node bT = null;
	Node next = null;//Next node
	//Each node needs to be judged and then linked to three linked lists.
	while(head !=null ){
		//The next two lines are to take out the head separately for comparison, and separate the part after the head from the head, so as to realize the separate comparison at each step
		next = head.next;
		head.next = null;
		if(head.value<pivot){
			if(sH == null){
				sH = head;
				sT = head;
			}else{
				sT.next = head;
				sT = head;
			}
		}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;
	}
	//Connect the less than and equal parts. If eT is empty, let eT = sT to prepare for connecting the later equal and greater parts.
	if(sT!= null) {
		sT.next = eH;
		eT = eT == null?sT:eT;
	}
	//All connections
	if(eT != null){
		eT.next = bH;
	}
	//Whether the first two of the three paragraphs are empty is also required in the last returned content.
	return sH != null ? sH :eH != null ? eH :bH ;
}

			

Copy a linked list with random pointer nodes

  1. Using hashmap
  2. First, the nodes are traversed. 1 - > 1 - > 2 - > 2 - > 3 - > 3 - > null, so that the next node of the node is its own copy node. You can link it through the random node, and find the corresponding next node at the same time, so that 1 'can find 3'. Finally, you can separate the new and old linked list and complete the copy of the whole linked list.
//The first method is to use hashmap to copy the whole linked list
public static Node copyListWithRand1(Node head){
	HashMap<Node,Node> map = new HashMap<Node,Node>();
	Node cur = head;
	while(cur != null){
		map.put(cur,new Node(cur.value));
		cur = cur.next;
	}
	cur = head;
	//In the main part of the copy, the next value of the key corresponding to the value of cur in the map is equal to the key corresponding to the next value of cur, and the original linked list and the linked list to be copied are connected by the key value pair, so as to realize the deep copy.
	while(cur != null){
		map.get(cur).next = map.get(cur.next);
		map.get(cur).rand = map.get(cur.rand);
		cur = cur.next;
	}
	return map.get(head);
}

public static Node copyListWithRand2(Node head){
	if(head == null){
		return null;
	}
	Node cur =head;
	Node next = null;
	//Copy all nodes and links
	while(cur != null){
		next = cur.next;
		cur.next = new Node(cur.value);
		cur.next.next = next;
		cur = next;
	}
	//The following two while loops are to copy the rand connection and the normal connection
	cur = head;
	Node curCopy = null ;
	while(cur != null){
		next = cur.next.next;
		curCopy = cur.next;
		curCopy.rand = cur.rand != null ? cur.rand.next:null;
		cur = next;
	}
	Node res = head.next;
	cur = head;
	//split
	while(cur != null){
		next = cur.next.next;
		curCopy = cur.next;
		cur.next = next;
		curCopy.next = next != null ? next.next :null;
		cur = next;
	}
	return res;
}

A series of problems on the intersection of two single chain tables

Judge whether there is a ring:

  1. Using hashset to traverse two single linked lists, we can judge whether the values in the linked list exist in the hashset, if there is a ring, if not, there is no ring.
  2. If you don't need a hash table, you need to prepare two pointers: fast pointer and slow pointer. The fast pointer will go two steps at a time and the slow pointer will go one step at a time. If there is a ring, the fast pointer and the slow pointer will meet on the ring. After the fast pointer and the slow pointer meet, adjust the fast pointer to the beginning of the linked list. At this time, press the fast pointer and the slow pointer one step at a time, and the first ring in node will meet again.
    Judge whether it intersects:
  3. If loop1 is empty and loop2 is empty, put all nodes of the list 1 into the map, traverse the list 2, find out whether the map exists in the map.
  4. Without map, we first traverse map1 to get the length of list 1 and the last node of list 1. Then traverse the length of list 2 and the last node of list 2. If end1 and end2 are equal, then compare the length of the list. If there are more parts, let the more parts go first, and then the two lists go at the same time. Finally, they will go to the place where they meet for the first time.
    It is impossible to intersect a ring and a acyclic in a single chain table structure.
  5. There are only three possible cases of a ring topology: as shown.
  6. loop1, loop2, head1, head2 are enough to distinguish three situations
    1) If loop1 is equal to loop2, it is case 2. If you cut off the part of the ring, it will be converted into the previous acyclic list structure.
    2) If loop1 is not equal to loop2, it is structure 1 or structure 3. Loop1 then goes down. If loop1 goes down and doesn't meet loop2, it doesn't intersect. If loop1 encounters loop2 during traversal, it intersects and returns loop1 or loop2
    At this time, only a limited number of variable spaces are used instead of hashmap.
public static Node getIntersectNode(Node head1,Node head2){
	if(head1 == null || head2 = null){
		return  null;
	}
	Node loop1 = getLoopNode(head1);
	Node loop2 = getLoopNode(head2);
	if(loop1 == null && loop2 == null){
		return noLoop(head1,head2);
	}
	if(loop1 != null && loop2 !=null){
		return bothLoop(head1,loop1,head2,loop2);
	}
	return null;
}
//The starting position of the ring according to the conclusion
public static Node getLoopNode(Node head){
	if(head == null || head.next == null || head.next.next){
		return null;
	}
	Node n1 = head.next;
	Node n2 = head.next.next;
	while(n1 != n2){
		if(n2.next == null || n2.next.next == null){
			return null;
		}
		n2 = n2.next.next;
		n1 = n1.next;
	}
	n2 = head;//n2 start again	
	while(n1 != n2){
		n1 = n1.next;
		n2 = n2.next;
	}
	return n1;
}

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 the last value of the two chains is different, there is no intersection between them
	if(cur1 != cur2){
		return null;
	}
	//This judgment is very ingenious. After determining which length, the cur is assigned directly
	cur1 = n >0 ?head1: head2;
	cur2 = cur1 == head1? head2:head1;
	//Find the absolute value
	n = Math.abs(n);
	//Finish the extra length first
	while(n!= 0 ){
		n--;
		cur1 = cur1.next;
	}
	while(cur1 != cur2){
		cur1 = cur1.next;
		cur2 = cur2.next;
	}
	return cur1;
}
public static Node bothLoop(Node head1,Node loop1,Node head2,Node loop2){
	Node cur1 = null ;
	Node cur2 = null;
	//If there is a common ring, it will be transformed into acyclic case to analyze, so as to find the starting position of intersection.
	if( loop1 == loop2){
		cur1 = head1;
		cur2 = head2;
		int n = 0;
		while(cur1 != loop1){
			n++;
			cur1 = cur1.next;
		}
		while(cur2 != loop2){
			n--;
			cur2 = cur2.next;
		}
		cur1 = n>0? head1: head2;
		cur2 = cur1 == head1 ? head2:head1;
		n = Math.abs(n);
		while(n!= 0){
			n--;
			cur1 = cur1.next;
		}
		while(cur1 != cur2){
			cur1 = cur1.next;
			cur2 = cur2.next;
		}
		return cur1;
	}else{
		cur1 = loop1.next;
		//It is judged that loop1 and loop2 are in different positions on the ring, and loop1 will surely pass loop2 when it rotates for one cycle, at this time, loop1 can be returned
		while(cur1 != loop1){
			if(cur1 == loop2){
				return loop1;
			}
			cur1 = cur1.next;
		}
		return null;
	}
}


Published 12 original articles, won praise 5, visited 270
Private letter follow

Posted by krystof78 on Sun, 02 Feb 2020 20:05:39 -0800