Recently found a course of high quality at a station, the following is the course notes!
Basic operation
Node structure
typedef struct{
int val;
Node* next;
}Node;
Find operation
Node* search(int val){
Node* pNode = root; // 根结点
while(pNode != nullptr)
if(pNode->val == val){
return pNode;
}
pNode = pNode->next;
}
return nullptr;
}
Delete operation – give the previous node of the node to be deleted
void delNode(Node* prev){
Node* curr = prev->next;
prev->next = curr->next;
delete curr;
}
Delete operation-give the node to be deleted
void delNode(Node* curr){
if(curr->next != nullptr){
Node* temp = curr->next;
curr->val = temp->val;
curr->next = temp->next;
delete temp;
}else{
Node* pNode = root; // 头节点
while(pNode->next != curr){
pNode = pNode->next;
}
pNode->next = nullptr;
delete curr;
}
}
Related algorithms
Deduplication of linked list elements
Remove Duplicates from Sorted List
Given a sorted linked list, delete all duplicates such that each element appear only once.For example, Given 1->1->2,return 1->2.Given 1->1->2->3->3, return 1->2->3
Node* deleteDuplicates(Node* head){
if(head == nullptr){
return nullptr;
}
Node* node = head;
while(node->next != nullptr){
if(node->val == node->next->val){
Node* temp = node->next;
node->next = temp->next;
delete temp;
}else{
node = node->next;
}
}
return head;
}
Dummy Node tips
Consider:
a. Which node's next pointer will be affected, you need to amend the pointer
b. If the node to be deleted is a memory space that is opened up dynamically, you need to release this part of the memory (c / c ++)
using dummy node is a very useful trick: as long as the uncertainty involved in the operation of the head node, the head node operation, might create the node dummy:
ListNode dummy = new new ListNode (0);
dummy-> = the Next head; *
.
.
Remove Duplicates from Sorted List ||
Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
For example,
Given 1->2->3->3->4->4->5,return 1->2->5.
Given 1->1->1->2->3, return 2->3
Node* deleteDuplicates(Node* head){
if(head == nullptr){
return nullptr;
}
Node* dummy = new Node(0);
dummy->next = head;
Node* node = dummy;
while(node->next != nullptr && node->next->next != nullptr){
if(node->next->val == node->next->next->val){
int val_pre = node->next->val;
while(node->next != nullptr && val_pre == node->next->val){
Node* temp = node->next;
node->next = temp->next;
delete temp;
}
}else{
node = node->next;
}
}
return dummy->next;
}
Given a linked list and a value, write a reorder to rearrange the linked list so that the small ratio is all to the left and the large ratio is to the right
Node* partition(Node* head, int x){
if(head == nullptr){
return nullptr;
}
Node* dummyleft = new Node(0);
Node* dummyright = new Node(0);
Node* left = dummyleft;
Node* right = dummyright;
Node* node = head;
while(node->next != nullptr){
if(node->val < x){
left->next = node;
left = left->next;
}else{
right->next = node;
right = right->next;
}
node = node->next;
}
left->next = dummyright->next;
right->next = nullptr;
return dummyleft->next;
}
Catch pointer skills
For the problem of finding a specific position of the list, you may use two chaser and runner to traverse the list at different speeds to find the target position: Node chaser = head, runner = head. And you can use a simple small test case to verify
Find the midpoint of a linked list
Node* midpoint(Node* head){
if(head == nullptr){
return nullptr;
}
Node* chaser = head, runner = head;
while(runner && runner->next){
runner = runner->next->next;
chaser = chaser->next;
}
return chaser;
}
Find the penultimate k node of the linked list
Node* findkthtoLast(Node* head, int k){
if(head == nullptr || k < 0){
return nullptr;
}
Node* runner = head;
Node* chaser = head;
while(k){
runner = runner->next;
}
if(runner == nullptr){
return nullptr;
}
while(runner->next != nullptr){
runner = runner->next;
chaser = chaser->next;
}
return chaser;
}
Given a linked list with rings, find the node where the ring starts
Analysis: To find a specific location, use the runner technique. Runner traverses at twice the speed, assuming there is a loop, then runner and chaser must be able to meet at a certain point. After the encounter, let chaser trigger from the head to catch up with the runner again, and the node of the second encounter is the position where the loop starts
How to judge whether two singly linked lists have an intersection
Move the node after the kth element of the linked list to the front
Example:
list = 10->20->30->40->50->60 k = 4
change to 50->60->10->20->30->40
void rotate(Node** root, int k){
if(k == 0){
return;
}
Node* current = root;
for(int count = 1; count < k && current != nullptr;count++){
current = current->next;
}
if(current == nullptr){
return;
}
Node *kthNode = current;
while(current->next != nullptr){
current = current->next;
}
current->next = root;
root = kthNode->next;
kthNode->next = nullptr;
}
.
Pattern recognition
1. When traversing the linked list, note that only one or a pair of nodes is processed per loop. The core node only handles the current one, otherwise it is easy to have repeated processing problems.
.
Reverse linked list
Reverse Linked List
Reverse the linked list and return the new head.
—递归版本—
Node* reverseList(Node* head){
if(head == nullptr){
return nullptr;
}
Node* prev = nullptr;
while(head != nullptr){
Node* curr = head;
head = head->next;
curr->next = prev;
prev = curr;
}
return prev;
}
—Non-recursive version—
Node* reverseList(Node* head){
if(head == nullptr){
return head;
}
if(head->next == nullptr){
return head;
}
Node* newHead = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return newhead;
}
.
Pattern recognition
2. Swap Node problem
3. If two nodes are swapped, if there is no deletion, the next pointers of the two nodes' prev nodes and the next pointers of these two nodes will be affected. It is always possible
a. First exchange the values of the next pointers of the two prev nodes
b. Then exchange the values of the next pointers of the
two nodes Regardless of the relative and absolute positions of the two nodes, the above processing method always holds
.
Swap two adjacent nodes
Swap Adjacent Nodes
Given a linked list,swap every two adjacent nodes and return its head.
Node* swapPairs(Node* head){
if(head == nullptr){
return head;
}
Node* dummy = new Node(0);
dummy->next = head;
Node* prev = dummy;
Node* node1 = head;
Node* node2 = head->next;
while(node1 && node1->next != nullptr){
node2 = node1->next;
prev->next = node1->next;
node1->next = node2->next;
node2->next = node1;
prev = node1;
node1 = prev->next;
}
return dummy->next;
}
.
Pattern recognition
3. The process two linked list problems, circulatory conditions generally can use while (l1 && l2), and then handle the rest of the list of non-NULL In this case, the boundary case special treatment, the conventional case conventional treatment.
.
Linked list addition
Add List Sum
Given two linked lists, each element of the lists is a integer. Write a function to return a new list, whick is the “sum” of the given two lists.
Part a. Given input (7->1->6) + (5->9->2), output 2->1->9.
Part b. Given input (6->1->7) + (2->9->5), output 9->1->2.
Part a–
Node* addTwoNumbers(Node* l1, Node* l2){
Node dummy(0);
Node* p = &dummy;
int cn = 0;
while(l1 || l2){
int val = cn + (l1 ? l1->val : 0) + (l2 ? l2->val : 0);
cn = val / 10;
val = val % 10;
p->next = new Node(val);
p = p->next;
if(l1){
l1 = l1->next;
}
if(l2){
l2 = l2->next;
}
}
if(cn != 0){
p->next = new Node(cn);
p = p->next;
}
return dummy->next;
}
Partb-
Problem analysis: For a, the solution of the front node does not depend on the rear node, so it is sufficient to traverse the solution in sequence. For b, the solution of the front node depends on the back node (carry), so it must be processed by recursion or stack. And, the result returned by subproblem can be a custom structure (carry + sub-list). Of course, you can also use the solution of a after solving the reverse list.
Combine two or more sorted linked lists
Merge Two Sorted List
Merge two sorted linked lists and return it as a new list.
Node* mergeTwoLists(Node* l1, Node* l2){
Node* dummy = new Node(0);
Node* curr = dummy;
while(l1 && l2){
if(l1->val <= l2->val){
curr->next = l1;
l1 = l1->next;
}{
curr->next = l2;
l2 = l2->next;
}
curr = curr->next;
}
curr->next = (l1 != nullptr) ? l1 : l2;
return dummy->next;
}
Merge K Sorted List
Node* mergeKLists(vector<Node*>&lists){
if(lists.size() == 0)return nullptr;
Node* p = lists[0];
for(int i = 0; i < l1sts.size(); i++){
p = mergeTwoLists(p, lists[i]);
}
return p;
}
Not finished!