According to the algorithm problem of more than 20 linked lists above Leetcode, this paper summarizes several techniques in the chain list operation.
1. Fast and Slow hands
The fast pointer is to use two pointers when traversing the linked list, and the quick pointer runs one or more steps more than the slow pointer, or the fast pointer runs n steps. This only needs to traverse once to find the last nth node, and to find the middle node, no additional space is needed to determine if the linked list has loops. For example, to find the middle node of a linked list,
ListNode * FINDMID (ListNode * head) { && head->next); *slow = head; *fast = head->next; while (Fast && fast->next) { = slow->next; = Fast->next->next; } return slow; }
We just need to move the slow pointer forward one at a time, and the fast pointer advances two bits at a time, and when the fast pointer points to the end, slow is just the midpoint of the list. As another example, when we delete the nth node, we simply forward the back pointer to N, then the two pointers go at the same speed, until the end of the list, Front->next points to the nth node of the bottom.
listnode* Removenthfromend (listnode* head,intN) {ListNode* Front =Head; ListNode* back =Head; for(inti =0; I < n; i++) Back= back->Next; if(Back = =NULL) {ListNode* TMP =Head; Head= head->Next; Deletetmp; returnHead; } while(Back->next! =NULL) {Front= front->Next; back= back->Next; } ListNode* tmp = front->Next; Front->next = tmp->Next; Deletetmp; returnHead; }
When judging whether a linked list has a ring, slow and fast each have their own forward and two steps, and if there is a ring, they will eventually gather together.
bool hascycle (ListNode *head) { ifreturnfalse; * Fast = head->next; * slow = head; while (FAST! = NULL && Fast->next! = null && slow! = fast) { = fast->next->next;
= slow->next; } return (FAST! = NULL && fast->next! = null); }
2. Virtual node
When an operation on a linked list changes the head pointer, you can add a dummy node before the head node, and then delete it when the list operation ends, which reduces unnecessary judgment and makes the code more concise and more readable. For example, when you delete a node of a given value, the node may be in the middle of the list, or it may be the head node, and when it is the head node, you need to modify the list header pointer, and add a virtual node that does not need the relationship to delete the head node or the middle node.
listnode* removeelements (listnode* head,intval) {ListNode* Dummy =NewListNode (-1); Dummy->next =Head; ListNode* prev =dummy; ListNode* p =Head; while(P! =NULL) { if(P->val = =val) {prev->next = p->Next; Deletep; } Else{prev=p; } P= prev->Next; } head= dummy->Next; Deletedummy; returnHead; }
As another example, when inserting a node in an arbitrary position in a linked list, we must find the previous node in the insertion position, and if it is the head node, it requires more judgment, and each step does not know whether the inserted position is before the head node, so the added virtual node makes the code more concise without concern for the problem. such as LEETCODE86 partition list
listnode* partition (listnode* head,intx) {ListNode* Dummy =NewListNode (-1); Dummy->next =Head; ListNode* prev =dummy; ListNode* First =Head; while(First! = NULL && First->val <x) { First= first->Next; Prev= prev->Next; } if(first = NULL | | first->next = =NULL) { Deletedummy; returnHead; } ListNode* p = first->Next; ListNode* Q =First ; while(P! =NULL) { if(P->val <x) {Q->next = p->Next; P->next = prev->Next; Prev->next =p; P= q->Next; Prev= prev->Next; } Else{p= p->Next; Q= q->Next; }} head= dummy->Next; Deletedummy; returnHead; }3. Fake delete operation
When we delete a node we have to know its previous node pointer, and as the beauty of programming is to delete a single-linked list in the middle node of the problem, only given a pointer to delete nodes, then we can not get the previous node pointer. You can then take the false delete operation, assign the value of the next node to the node, and then delete the next node. This technique can also be used in some other places (I haven't seen it yet, but it's a good algorithm to use a simple and efficient algorithm anyway).
4. Problem switching
Determine if a single-linked list has a ring problem, if you still need to find this intersection node? We can change the problem, the front in the fast and slow pointer to determine whether a linked list has a ring when the ring has been found a node pointer, then we from this node to break the list becomes another problem, that is, to determine whether the two non-ring single linked list is a cross problem. This problem is in the beauty of programming, such as.
A: a1→a2 c1→c2→c3 B: b1→b2→b3
How can we solve this problem? We think that if the two linked lists have common nodes, then from the last node to the intersection are their common nodes. If the two linked list is as long as that, the problem is good to do, as long as two linked lists at the same time, will always point to the intersection node. Now you know, using the idea of a fast and fast pointer, first get the length of two linked lists, and then let the long table of the traversal pointer first run a distance, so that they start from the same distance from the end of the link, so that the intersection can be found. Now summarize the single linked list with the ring Problem II step is:
1. A single linked list with a ring problem I, get a pointer in the ring.
2. Disconnect the ring with the resulting pointer.
3. Solve the cross-node problem of two single linked lists, and get the final result.
ListNode *detectcycle (ListNode *head) { if(head = = NULL | | head->next = = NULL)returnNULL; ListNode* Slow =Head; ListNode* Fast = Head->Next; while(FAST! = NULL && Fast->next! = null && Slow! =fast) {Slow= slow->Next; Fast= fast->next->Next; } if(Fast = = NULL | | fast->next = =NULL) { returnNULL; } ListNode* Tail1 =slow; ListNode* Head2 = slow->Next; Tail1->next =NULL; intLength1 =0; ListNode* p =Head; while(P! =NULL) {length1++; P= p->Next; } intLength2 =0; P=head2; while(P! =NULL) {length2++; P= p->Next; } ListNode* Newhead1 =Head; ListNode* Newhead2 =head2; if(Length1 >length2) { intK = length1-length2; while(k-->0) Newhead1 = newhead1->Next; } Else if(Length2 <length1) { intK = length2-length1; while(k-->0) Newhead2 = newhead2->Next; } while(Newhead1! =newhead2) {Newhead1= newhead1->Next; Newhead2= newhead2->Next; } tail1->next =head2; returnNewhead1; }
As another example, when reversing the list problem, the problem II reverses the middle part of [m,n], so you can handle it first, mark the left End node and the right-hand node, reverse the middle part, and then link it up. Of course not, because the direct anti-transfer is a little better.
Waring Source: http://www.cnblogs.com/waring Welcome to reprint or share, but be sure to declare the source of the article.
Several efficient techniques for linked list operations