1. Linearity table

linear list is a finite sequence of n data elements with the same characteristics. It is a data structure widely used in practice. The common linear lists are: sequential list, linked list, stack, queue, string
A linear table is logically a linear structure, that is, a continuous straight line. However, the physical structure is not necessarily continuous. When the linear table is stored physically, it is usually stored in the form of array and chain structure.
Array storage It can be stored completely or there can be space left

Store in chain structure This is a simple single linked list (one-way headless acyclic linked list). The specific structure will be introduced in detail later.

2. Sequence table

2.1 concept and structure

Data structure: describes how data is organized.
A sequence table is a data structure. Its bottom layer is an array.
Sequential table is a linear structure in which data elements are sequentially stored in a storage unit with continuous physical addresses. Generally, array storage is used to complete the addition, deletion, query and modification of data on the array.
In order to better understand the sequence table, the following figure can help you better understand it. The upper row indicates where data is stored, while the lower row indicates the number of data in the linked list.

The sequence table can generally be divided into:

• Static sequential table: use fixed length array storage.
• Dynamic sequential table: use dynamic array storage.

The static sequence table is suitable for determining the scenario that knows how much data needs to be stored. The fixed length array of static sequence table leads to large N, waste of space and insufficient space.
In contrast, the dynamic sequential table is more flexible and dynamically allocates space according to needs.

2.2 interface implementation

In the above, we use icons to show the sequence table. In Java, we should construct these things according to this idea to let the JVM know what the code we write represents.
Next, we will implement the interface of the sequence table. The following is the code:

import java.util.Arrays;

public class MyArrayList {
public int[] elem;//Array reference type (on heap) to store data
public int usedSize;//Number of valid data

public MyArrayList() {//Initializing an array with a constructor
this.elem = new int;//Let this Elem equals the new integer array
}
}

-In the above code, we first created elme, which is used to open up space on the heap and store arrays;
-Then we create usedSize, which is used to record how many data there are in the sequence table.
-Then we use the constructor to initialize the array so that the array can be stored in the sequence table.

Interface 1: add an element at a certain position in the sequence table

//Add new element in pos position
public void add(int pos, int data) {
//1. Judge whether the array is full
if (isFull()) {
System.out.println("The sequence table is full! Capacity expansion required!");
this.elem = Arrays.copyOf(this.elem,2*this.elem.length);//The expanded array still has to be assigned to the original this elem
//return;
}
//2. First judge the legitimacy of pos location
if (pos < 0 || pos > this.usedSize) {
System.out.println("pos Illegal location!!!");
return;
}
//3. Move the element from back to front. If pos==usedSize, put it directly to the usedSize position
if (pos == this.usedSize) {
this.elem[pos] = data;
this.usedSize++;
return;
}
for (int i = this.usedSize - 1; i >= pos; i--) {
this.elem[i + 1] = this.elem[i];
}
this.elem[pos] = data;
this.usedSize++;
}
public boolean isFull() {
if (this.usedSize == this.elem.length) {
return true;
}
return false;
}

When we add elements to the sequence table, we can fill them or have vacancies. When the number of added elements is greater than its space, we can expand the capacity. After capacity expansion, the expanded table should be assigned back to the original table.

In this way, our interface for inserting data into the sequence table is established. In order to check whether it is correct, we also need to create a printing method to check whether the inserted data conforms to our design idea.

Note: when inserting elements in the sequence table, there must be elements in front of the insertion position, otherwise it is illegal!!!

Interface 2: printing method

// Print sequence table
public void display() {
for (int i = 0; i < this.usedSize; i++) {
System.out.print(this.elem[i]+" ");
}
System.out.println();
}

The idea of printing is the same as that of printing the elements in the array. We can see that the introduction of usedSize can greatly improve the efficiency of the code, rather than re writing the code to obtain how many data there are in the sequence table.
After these two preparations are made, we can check whether we have correctly inserted data in the main function.

public static void main(String[] args) {
MyArrayList myArrayList = new MyArrayList();
myArrayList.display();
}
//Output: 1,2,3,4

First of all, you have to instantiate the class where the call sequence table is located. Because the array is stored in the sequence table, its starting position starts from 0, which should be noted.

Interface 3: judge whether the sequence table contains an element

// Determines whether a toFind element is included
public boolean contains(int toFind) {
for (int i = 0; i < this.usedSize; i++) {
if(this.elem[i] == toFind) {
return true;
}
}
return false;
}

Idea: use the for loop to traverse the sequence table.

Interface 4: find the corresponding position of an element

// Find the location of an element
public int search(int toFind) {
for (int i = 0; i < this.usedSize; i++) {
if(this.elem[i] == toFind) {
return i;
}
}
return -1;
}

Idea: use the for loop to traverse the sequence table. If found, return the subscript of the location of the element. If not found, return - 1, because the subscript of the sequence table is the same as that of the array, which starts from 0 by default.

Interface 5: get the element of a location

//Gets the element of the pos location
public int getPos(int pos) {
//1. Judge whether the sequence table is empty
if(this.isEmpty()) {
return -1;
}
//2. Illegal POS
if(pos < 0 || pos >= this.usedSize) {
return -1;//-1 is used to mark that the current position is illegal
}
//3. Return the element at that location
return this.elem[pos];
}
public boolean isEmpty() {
/*if(this.usedSize == 0) {
return true;
}
return false;*/
return this.usedSize == 0;
}

Idea:

• First, we have to judge whether the sequence table is empty;
• Next, judge whether the obtained position conforms to the sequence table we created;
• If the above two conditions are reasonable, the data can be returned directly.

Interface 6: setting elements for a location

//The element at pos position is set to value
public void updatePos(int pos, int value) {
//1. Judge whether the sequence table is empty
if(this.isEmpty()) {
return;
}
//2. Illegal POS
if(pos < 0 || pos >= this.usedSize) {
return;
}
//3. Set value
this.elem[pos] = value;
}

Idea:

• First, you have to judge whether the sequence table is empty;
• Secondly, judge the legitimacy of the location of the updated data;
• If the above two conditions are reasonable, you can set the element directly.

Interface 7: delete the first keyword key

//Delete the keyword key that appears for the first time
public void remove(int key) {
int index = search(key);//Find the keyword and return its subscript
if(key == -1) {
System.out.println("Keywords you want to delete:"+key+"non-existent!!");
return;
}
for (int i = index; i < this.usedSize-1; i++) {//When i move, i can't move back after i move the last number, so i have to set a reasonable condition i < this usedSize-1
this.elem[i] = this.elem[i+1];
}
this.usedSize--;
}

Idea:

• First, we have to find the location of this keyword with the help of interface 4;
• Secondly, judge the legitimacy of location;
• Finally, directly move the data behind the keyword forward to complete the deletion. At the same time, the usedSize value also needs to be changed accordingly.

The data of the deletion sequence table can be understood as follows: Other interfaces: get the length of the table and clear the sequence table

// Get sequence table length
public int size() {
return usedSize;
}
// Empty sequence table
public void clear() {
this.usedSize = 0;
}

Question:

1. The time complexity of inserting and deleting sequence tables is O(N)
2. Capacity expansion requires applying for new space, copying data and releasing old space, which will consume a lot.
3. The capacity increase is generally double, which is bound to waste some space.

Based on the above shortcomings, we introduce linked list.

3.1 concept and structure of linked list

Linked list is a discontinuous storage structure in physical storage structure. The logical order of data elements is realized through the reference link order in the linked list. Generally speaking, a linked list is connected by nodes.

In practice, the structure of linked list is very diverse. There are eight linked list structures when the following situations are combined:

• Unidirectional and bidirectional
• Cyclic and non cyclic

The linked list is formed by connecting nodes. The node structure is as follows: We can see that a node has two fields, one is data and the other is address. The single linked list is connected by such nodes. As can be seen from the above figure:

• Each node of the single linked list has two fields, the upper part is data, and the lower part is a reference (address) to the next node;
• The first node is the head node and the last node is the tail node;
• Each node has a reference (address);
• Nodes are connected through next.

By comparing the graph structure of sequence list and linked list, we can see that sequence list is physically and logically continuous; The linked list is not necessarily continuous physically, but must be continuous logically. It has a header node, but the header node does not store data. In the next study, we first get familiar with the single linked list without taking the lead. On this basis, we get familiar with the linked list.

Supplement:  In order to implement a single linked list, we need to define a Node node in the code, which is also a class. In this class, we need to specify two parts, one is data, and the other represents the address of the next Node; Then, the construction method is used to instantiate the data of each Node. The code can be written as:

//Node is a class
class Node {//Defines a node that has two values
public int val;//Integer data
public Node next;//Address of the next node

public Node(int val) {
this.val = val;
}
}

Then we create a linked list class, in which we can call the properties of the node.
First define a header node, and then insert data into the linked list by enumeration. The code is as follows:

//Create a single linked list in an exhaustive way
public void creatList() {
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
node1.next = node2;
node2.next = node3;
node3.next = node4;
}
}

In the above code, we call the Node class and instantiate four objects, and then make the reference of each object point to the reference of the next Node. In this way, nodes are connected.

Then, in the class MyLinkedList, in order to check whether the data of the linked list is instantiated successfully, we have to create a printing function:

Interface 1: print function

public void show() {
/*while (this.head != null) {//Disadvantages of this method: the value saved in the last head is null, that is, the head is missing

Node cur = this.head;//It can ensure that the head is always in front. Moving only cur
while (cur != null) {
System.out.print(cur.val+ " ");
cur = cur.next;
}
System.out.println();
} The printing function can be written as the above two, but the second one is preferred. We can see from the print function in the note that the head is used to traverse the whole linked list. After traversing the linked list, the head is at the back, which is inconsistent with our design concept. Therefore, in the following code, we define a new node cur to traverse the array instead of the head node. In this way, the rationality of the code is improved.

Through the above two interfaces, we can completely create a linked list, but the method is too low. If a large amount of data needs to be inserted into the linked list, the efficiency of the code will be reduced, so we have this method to establish the linked list. Plug in:

As the name suggests, the head insertion method is to insert nodes from the head of the linked list, and each newly inserted node is the head node of the linked list.

Node node = new Node(val);//The first step is to define the data to be inserted
}

We have defined the header node in the class MyLinkedList. Therefore, in the process of header interpolation, we can draw a picture as follows:
Step 1: define that the head node is empty, and the inserted node defines a new data. Step 2: let the next of the inserted node point to the head node, and then the head is equal to node, then the first data newly inserted is the head node of the new linked list. Step 3: continue to insert new data Repeat the step in step 2 to make the next of the inserted node equal to the address of the head node. In this way, the two nodes are connected together because of this address. The node points to the head from the node, and the head is equal to the address of the newly inserted node. Then the newly inserted node is the head node of the new linked list. After that, the new node inserted can complete the head insertion method by repeating the step in step 2.

Interface 3: tail insertion method

Tail insertion method is to insert nodes from the tail node of the linked list, and each newly inserted node is the tail node of the new linked list.

//● tail interpolation
Node node = new Node(val);
if(this.head == null) {//When there is no node
}else {
while (cur.next != null) {
cur = cur.next;
}
//Cycle here, cur next == null;
cur.next = node;
}
}

Firstly, we consider the tail interpolation method with multiple nodes.

• First define a cur to traverse the linked list instead of head When next = null, the corresponding cycle ends;
• Then let's go to cur at the current tail node Next = address of the node to be inserted.
• The special case is: if the linked list is empty, you can directly make the node node equal to the head node.

Interface 4: plug in at any position

public Node searchIndexSubOne(int index) {//The specified index was found
/*while(index-1 != 0) {
cur = cur.next;
index--;
}*/
int count = 0;
while (count != index - 1) {//Determines whether the number of moves is equal to the specified subscript minus one
cur = cur.next;
count++;
}
return cur;//Moved to the designated position
}
//● insert at any position, and the first data node is subscript 0
public void addIndex(int index,int data) {
if(index < 0 || index > getLength()) {
System.out.println("Illegal location!!");
return;
}
if(index == 0) {
return;
}
if(index == getLength()) {
return;
}
Node ret = searchIndexSubOne(index);
//ret stores the address (Reference) of the node at index-1
Node node = new Node(data);//Set inserted data
node.next = ret.next;//The address of the inserted data is equal to the address moved to the specified location
ret.next = node;//The address of ret moved to the specified location is equal to the reference of node
}
public int getLength() {
int len = 0;
while (cur != null) {
len++;
cur = cur.next;
}
return len;
}

General idea: insert at any position:

• Insert at the head node, which is equivalent to the head insertion method;
• Inserting at the tail node is equivalent to tail interpolation;
• Insert at a given position, find the inserted node according to a certain method, and then insert it.

Now let's discuss the third case:
To insert at any position, we have to find this position. From the figure, we can infer that assuming that the inserted position is the position with index 2, we only need to move cur to the previous node at position 2 to ensure that the new nodes can be connected. Then the relationship between cur and index is cur = index -1. We can use the loop, Calculate the number of times cur is moved, and then find the index. In this case, the insertion can be simply completed. Interface 5: check whether there is a keyword in the linked list

//● check whether the keyword is included and whether the key is in the single linked list
public boolean contains(int key) {
while(cur != null) {
if(cur.val == key) {
return true;
}
cur = cur.next;
}
return false;
}

The above interface is implemented. The implementation of this interface is very simple. You only need to traverse the linked list once to determine whether the keyword is in the linked list.

Interface 6: delete the node whose keyword is key for the first time

General idea: the node to be deleted is not the head node or tail node
As shown in the figure below, assuming that we want to delete the third node, we only need to find the precursor node of the node to be deleted and directly let cur The value of next is equal to the address of the last node. But how to find the node to be deleted and its precursor node cur only after traversing the linked list once? At this point, you need to write a method to find the precursor node. The following code is easy to understand.

//Find the precursor of key from the beginning
public Node searchPrev(int key) {
while(cur.next != null){
if(cur.next.val == key) {//Judge that the next value of the current node is not equal to key
return cur;//If equal to, this node is the precursor
}
cur = cur.next;
}
//When the cycle is finished, it means that it is not found
return null;
}
//● delete the node whose keyword is key for the first time
public void remove(int key){
//1. Judge whether the header node is the node to be deleted
return;
}
//2. Find the precursor node of the key. The reason for finding the precursor node: if the deleted node is in the middle of the linked list and the deleted node is gone, the reference of the precursor node must be changed to the node of the deleted data, so that the linked list is complete
Node prev = searchPrev(key);
if(prev == null) {
System.out.println("There is no node to delete!");
return;
}
//The specified deletion location was found
Node del = prev.next;//del is a node
//Start deletion
prev.next =del.next;
}

Overall idea:

• First judge whether the end node is the node to be deleted;
• Then find the precursor node;
• Next, find the node to delete;
• Finally, you can delete it directly.

Interface 7: delete all nodes with key value

Idea: to delete a node, you have to find the precursor node of the node. Consider the case where multiple values need to be deleted, and also consider the case where the header node is to be deleted. cur is equivalent to the node to be deleted.

//Delete all nodes with the value of key
public void removeAllKey(int key) {
//Each element of the single linked list should be traversed
while (cur != null) {
if (cur.val == key) {
//This is the node you want to delete
prev.next = cur.next;
cur = cur.next;
}else {
prev = cur;//Or prev = prev next;
cur = cur.next;
}
}
}
}

Interface 8: clear single linked list

Idea: you can directly make the head node null, or write a loop to make each node empty in the process of traversing the linked list. We also have to consider the case of only one node.

public void clear() {
while (cur != null) {
Node curNext = cur.next;
cur.next = null;
cur = curNext;
}
}

Headless two-way linked list is similar to single linked list. It is connected by nodes, but each node has three fields: the first field represents the number of the current node, the second field represents the address of the predecessor node of the current node, and the third field represents the address of the next node. As shown in the figure below, it points to a simple headless two-way linked list. To implement a headless two-way linked list, similar to a single linked list, create a ListNode class, define the data, the address of the precursor node and the address of the next node in this class, and then assign values to the nodes of the class by the construction method:

class ListNode {
public int val;
public ListNode prev;
public ListNode next;

public ListNode(int val) {
this.val = val;//point
}
}

Interface 1: print function

Next, create a MyDoubleList class to represent the headless bidirectional linked list. All interfaces of the headless bidirectional linked list will be implemented in this class

public class MyDoubleList {
public ListNode tail;//tail

//Printing method
public void display() {
while (cur != null) {
System.out.print(cur.val + " ");
cur = cur.next;
}
System.out.println();
}
}

ListNode node = new ListNode(data);
if (this.head == null) {//First insertion
this.tail = node;
}else {
}
}

Interface 3: tail insertion method

//Tail interpolation
ListNode node = new ListNode(data);
if (head == null) {//First insertion
this.tail = node;
}else {
this.tail.next = node;
node.prev = this.tail;
this.tail = this.tail.next;
}
}

Interface 4: plug in at any position

//Find the subscript where the node is located
public ListNode findIndex(int index) {
int count = 0;
while (count != index) {
cur = cur.next;
count++;
}
return cur;
}

//Insert at any position, and the first data node is subscript 0
public void addIndex(int index,int data) {
if (index <0 || index >size()) {
System.out.println("index wrongful!!");
return;
}
if (index == 0) {
return;
}
if (index == this.size()) {
return;
}
ListNode cur = findIndex(index);
ListNode node = new ListNode(data);
node.next = cur;
cur.prev.next = node;
node.prev = cur.prev;
cur.prev = node;
}

Interface 5: check whether the keyword key is in the linked list

//Find out whether the keyword is included and whether the key is in the linked list
public boolean contains(int key) {
while (cur != null) {
if (cur.val == key) {
return true;
}
cur = cur.next;
}
return false;
}

Interface 6: delete the node whose keyword is key for the first time

//Delete the node whose keyword is key for the first time
public void remove(int key) {
while (cur != null) {
if (cur.val == key) {
if (this.head != null) {//The linked list has only one node and needs to be deleted
}else {
this.tail = null;
}
}else {//Middle and tail nodes
if (cur.next != null) {//middle
cur.prev.next = cur.next;
cur.next.prev = cur.prev;
}else {//Tail node
cur.prev.next = cur.next;
tail = cur.prev;
}
}
return;
}else {
cur = cur.next;
}
}
}

Interface 7: delete all nodes with key value

//Delete all nodes with the value of key
public void removeAllKey(int key) {
while (cur != null) {
if (cur.val == key) {
if (this.head != null) {//The linked list has only one node and needs to be deleted
}else {
this.tail = null;
}
}else {//Middle and tail nodes
if (cur.next != null) {//middle
cur.prev.next = cur.next;
cur.next.prev = cur.prev;
}else {//Tail node
cur.prev.next = cur.next;
tail = cur.prev;
}
}
}
cur = cur.next;
}
}

Interface 8: get the length of the linked list

//Get the length of the linked list
public int size() {
int count = 0;
while (cur != null) {
cur = cur.next;
count++;
}

return count;
}

public void clear() {
while (cur != null) {
ListNode curNext = cur.next;
cur.next = null;
cur.prev = null;
cur = curNext;
}
this.tail = null;
}

3.3 chain surface test questions

1. Delete all nodes in the linked list equal to the given value val

Force buckle topic: Remove linked list elements.
The code of this problem is the same as the code of interface 7 mentioned above, but it needs to be judged when the force buckle is applied:

if (head == null) return null;//If there is no node in the linked list, null will be returned and nothing can be deleted

Then return a head at the end of the code to run.

Force buckle topic: Reverse a single linked list.

Reversing the linked list means that the node is reversed, that is, the node points backwards. As shown below: Idea 1: use the head insertion method to check the nodes behind the original linked list to the front of the head node.

/**
* @return
*/
public Node reverseList() {
}
//cur represents a node that is currently to be flipped or headlined
Node curNext = cur.next;
cur.next = null;
cur = curNext;
curNext = cur.next;
cur = curNext;
}
}
/**

Idea 2: define a precursor node with the following code:

/**
* New method: define a precursor node
* @return
*/
public Node reverseList1() {
Node prev = null;
while (cur != null) {
Node curNext = cur.next;
if (curNext == null) {
}
cur.next = prev;
prev = cur;
cur = curNext;
}
}

Since a new header node is defined when the reverseList1() class is written, a new show2 method needs to be called when checking:

//Start printing according to the specified node position (this printing function is used in conjunction with the method reverseList1())
while (cur != null) {
System.out.print(cur.val + " ");
cur = cur.next;
}
}

3. Return the intermediate node of the linked list

Force buckle topic: Returns the intermediate node of the linked list.
Title Description: given a non empty single linked list with head node, return the intermediate node of the linked list. If there are two intermediate nodes, the second intermediate node is returned.

Idea: the speed node defines a fast, two steps at a time, and defines a slow node, one step at a time, when fast or fast When next is null, the position of slow is the position of the intermediate node. This idea is applicable to odd and even nodes.

/**
* Given a non empty single linked list with head node, return the intermediate node of the linked list. If there are two intermediate nodes, the second intermediate node is returned
* @return
*/
public Node middleNode() {

while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}

4. Input a linked list and output the penultimate node in the linked list

Idea: to output the penultimate node, you need to define two nodes, fast and slow. Fast takes the k-1 step first, and then slow and fast go together when fast or fast When next is null, the position of slow is the penultimate node.

Note: judge the rationality of k value; Judge the condition of empty linked list

/**
* Input a linked list and output the penultimate node in the linked list.
* @param k
* @return
*/
public Node findKthToTail(int k) {
if(k <= 0 || head == null) {
return null;
}
while (k-1 != 0) {
if (fast.next != null) {
fast = fast.next;
k--;
}else {
System.out.println("Given k The value is too big!!");
return null;
}
}
//Here, fast took k-1 steps
while(fast.next != null) {
fast = fast.next;
slow = slow.next;
}
return slow;
}

Title Description: write code to divide the linked list into two parts based on the given value x. all nodes less than x are arranged before nodes greater than or equal to x.

Idea: as shown in the figure below. A single linked list with 5 nodes. Assuming a given x = 30, we can insert the number smaller than 30 into the front line segment, insert the number larger than 30 into the rear line segment, and finally connect the two line segments into a linked list. Note: after thinking according to the above ideas, we need to pay attention to some special situations.

• 1. First consider the first insertion and not the first insertion of the two parts;
• 2. All data are smaller than the specified data, that is, all data are inserted into the first half, and the second half is empty, and vice versa;
• 3. There is just one node in the second half. You need to set the next value of the node to null, otherwise it will cause an endless loop.
/**
* Write code to divide the linked list into two parts based on the given value X. all nodes less than X are arranged before nodes greater than or equal to x, and the original data order cannot be changed. Return the head pointer of the rearranged linked list
* @param x
* @return
*/
public Node partition(int x) {
Node bs = null;//bs is the abbreviation of before start
Node be = null;//bs is the abbreviation of before end
Node as = null;//afterstart
Node ae = null;
while (cur != null) {
if (cur.val < x) {//Less than x
if(bs == null) {//First insertion of less than part
bs = cur;
be = cur;
}else {
be.next = cur;
be = be.next;
}
}else {//Greater than or equal to x
if (as == null) {//First insertion of greater than part
as = cur;
ae = cur;
}else {
ae.next = cur;
ae = ae.next;
}
}
cur = cur.next;
}
if (bs == null) {//Here, judge if the value of x is smaller than all the numbers in the linked list
}
be.next = as;//After traversing the linked list, connect the two separate parts
if (as != null) {//The last data is less than x and is placed in the first half. If there is no tail node in the whole linked list, it will enter an endless loop.
ae.next = null;//ae and as were together at the beginning, and ae moved behind
}
return bs;
}

6. Delete duplicate nodes in the linked list

Niuke topic: Delete duplicate nodes in the linked list.
Title Description: in a sorted linked list, there are duplicate nodes. Please delete the duplicate nodes in the linked list. The duplicate nodes are not retained and the chain header pointer is returned.

Idea: define a cur and let it traverse the linked list; Define a puppet node tmphead. First judge cur next != null && cur. val == cur.next. Val this condition, and then let tmpahead next = cur； tmpHead = tmpHead.next； Cur continues to traverse backwards. When encountering repeated numbers, write a loop and let cur continue to traverse backward. At the end of the loop, cur is at the last of the same number, and then jump out of the loop and let cur traverse a node later to make cur The value of next is equal to the tmpahead node, so the linked list is connected.

be careful:

• 1. Judge whether the linked list is empty;
• 2. Except for the head node, the numbers of other nodes are the same, so you need to pay attention to setting the next value of the head node to null. /**
* In a sorted linked list, there are duplicate nodes. Please delete the duplicate nodes in the linked list. The duplicate nodes are not retained and the chain header pointer is returned. For example, the linked list 1 - > 2 - > 3 - > 3 - > 4 - > 4 - > 5 is 1 - > 2 - > 5 after processing
* @return
*/
public Node deleteDuplication() {
Node tmpHead = new Node(-1);//Define a puppet node to ensure that one node is fixed.
Node newHead = tmpHead;//This considers that the linked list is the same from the beginning node, and only the tail node is different
while (cur != null) {
if (cur.next != null && cur.val == cur.next.val) {//Duplicate nodes found
while (cur.next != null && cur.val == cur.next.val) {
cur = cur.next;
}
cur = cur.next;
}else {//No duplicate nodes found
cur = cur.next;
}
}
}

This problem is a little more difficult and needs more practice

7. Palindrome structure

Niuke topic: Palindrome structure of linked list.
Title Description: for a linked list, please design an algorithm with time complexity of O(n) and additional space complexity of O(1) to judge whether it is palindrome structure.

Idea:

• First, use the speed node to find the intermediate node of the current linked list;
• Then reverse the second half of the linked list;
• When reversing, start from the next node of slow (the same applies to even nodes).

Note: consider the case of odd and even nodes /**
*For a linked list, please design an algorithm with time complexity of O(n) and additional space complexity of O(1) to judge whether it is palindrome structure,
*Given the header pointer A of A linked list, please return A bool value to represent whether it is A palindrome structure. Ensure that the length of the linked list is less than or equal to 900.
*    Test example: 1 - > 2 - > 2 - > 1
*    Return: true
* @return
*/
public boolean chkPalindrome() {
if (this.head.next == null) return true;//Only one node
while (fast != null && fast.next != null) {//Find the intermediate node with slow
fast = fast.next.next;
slow = slow.next;
}
Node cur = slow.next;
while (cur != null) {//Flip the second half of the linked list
Node curNext = cur.next;
cur.next = slow;
slow = cur;
cur = curNext;
}
return false;
}
if (this.head.next == slow) {//When the number of nodes is even
return true;
}
slow = slow.next;
}
return true;
}

Idea: as shown below. Define the speed node, a fast node and a slow node. Fast takes two steps at a time and slow takes one step at a time. When fast and slow meet again, it shows that the linked list has rings.

Q: why can't fast take only two steps, three or four steps?
A: two steps can ensure the fastest meeting. Three or four steps may be missed several times before meeting. /**
* @return
*/
public boolean hasCycle() {

while (fast != null  &&  fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
return true;
}
}
return false;
}

9. Return the first node of the linked list into the ring

Force buckle topic: Returns the first node of the linked list into the ring.
Title Description: given a linked list, return the first node from the linked list into the ring. If the linked list is acyclic, null is returned.

Idea: set two nodes, fast and slow. Fast takes two steps at a time and slow takes one step at a time.
Suppose in the linked list, as shown in the following figure, x is the number of nodes traversed before entering the ring, c is the length of the ring, the green part is the point met on the ring, and its distance from the node entering the ring is y. Since the speed of fast is twice that of slow, there is a double relationship between the distance when we meet.
When meeting:

• Slow node slow: x+c-y
• fast node: x+c+c-y

From the above relationship, we can deduce that x=y /**
* Given a linked list, return the first node from the linked list into the ring. If the linked list is acyclic, null is returned
* @return
*/
public Node detectCycle() {
while (fast != null  &&  fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
break;
}
}
if (fast == null  ||  fast.next == null) {
return null;
}
while (fast != slow) {
slow = slow.next;
fast = fast.next;
}
return slow;
}

Force buckle topic: Merge two ordered linked lists.

Title Description: merge two ascending linked lists into a new ascending linked list and return. The new linked list is composed of all nodes of a given two linked lists.

Idea: since we cannot determine which of the two nodes has a larger number of head nodes, we first define a puppet node newH, let tmpHead = newHead, and let tmpHead traverse the two linked lists instead of newHead. The following figure is an example: In the process of traversal, the two linked lists connect all nodes together according to the definition of single linked list, and the two linked lists are combined into an ordered single linked list. The steps in the figure above are as follows: /**
* Merge the two ascending linked lists into a new ascending linked list and return. The new linked list is composed of all nodes of a given two linked lists.
* @return
*/
Node newHead = new Node(-1);//Define a puppet node
}else {
}
}
if (head1 != null) {//In this case, one linked list has been traversed and the other has not been traversed. It directly points to the linked list that has not been traversed.
}
}
}

public static void main(String[] args) {

}

11. Two linked lists: find the common nodes of the two linked lists

Find the common nodes of the two linked lists.
Title Description: enter two linked lists and find their first common node. If the two linked lists do not have intersecting nodes, null is returned.

Idea: when two linked lists intersect, the result must be Y-shaped.
The following figure shows the results of the intersection of two linked lists. At this time, the length of head 1 is 4 and the length of head 2 is 5. Our main idea is to let the longer linked list take the absolute value step of their difference first, and then the two linked lists go together. When the two nodes meet for the first time, the node is what we want. /**
* Find the starting node where two single linked lists intersect
* @return
*/
//0. Judge whether it is empty
//1. Calculate the length of the two linked lists respectively
int lenA = 0;
int lenB = 0;
while (pl != null) {
lenA++;
pl = pl.next;
}
while (ps != null) {
lenB++;
ps = ps.next;
}
pl = headA;//Be sure to rewrite it back
int len = lenA - lenB;
if (len < 0) {
len = Math.abs(lenA-lenB);//The absolute value function is referenced here, which is equivalent to len = headb heada to ensure that len is a positive number
}
//pl must be a long list and ps must be a short list
while (len != 0) {//The difference of the first go length of the long linked list
pl = pl.next;
len--;
}//So far, the two linked lists are on the same starting line
while (pl != ps) {//Next, the two linked lists start walking synchronously
pl = pl.next;
ps = ps.next;
}
if (pl == null  ||  ps == null) {
return null;
}
return pl;
}

/**
* Find the starting node where two single linked lists intersect
* @param args
*/
public static void main17(String[] args) {

}