概述
203. 移除链表元素
707. 设计链表
206. 反转链表
24. 两两交换链表中的节点
- 上述四个题目,算法的技巧都在建立虚拟头结点,来统一操作
分析
思路
如何添加虚拟头结点?
代码
203
移除链表中满足Node.val == val 的节点,通过使用虚拟头结点来统一对原始链表头结点的删除操作
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode *virtual_head = new ListNode();
virtual_head->next = head;
ListNode *pre_ptr = virtual_head;
ListNode *work_prt = head;
while(work_prt) {
if (work_prt -> val == val) {
pre_ptr -> next = work_prt->next;
work_prt = pre_ptr->next;
} else {
pre_ptr = pre_ptr -> next;
work_prt = work_prt -> next;
}
}
return virtual_head -> next;
}
};
707
利用虚拟头结点来统一操作
class MyLinkedList {
public:
struct LinkNode{
int val;
LinkNode *next;
};
MyLinkedList() {
size = 0;
virtual_node = new LinkNode();
}
int get(int index) {
if (index < 0 || index >= size) return -1;
LinkNode *work_ptr = virtual_node;
int count = 0;
while(work_ptr -> next) {
work_ptr = work_ptr -> next;
if (count == index) return work_ptr -> val;
++count;
}
return -1;
}
void addAtHead(int val) {
LinkNode *new_node = new LinkNode();
new_node -> val = val;
new_node -> next = virtual_node -> next;
virtual_node -> next = new_node;
++size;
}
void addAtTail(int val) {
LinkNode *new_node = new LinkNode();
new_node -> val = val;
LinkNode *work_ptr = virtual_node;
while(work_ptr -> next) work_ptr = work_ptr -> next;
work_ptr -> next = new_node;
++size;
}
void addAtIndex(int index, int val) {
if (index <= 0) {
addAtHead(val);
return;
}
if (index == size){
addAtTail(val);
return;
}
if (index > size) return;
LinkNode *new_node = new LinkNode();
new_node -> val = val;
LinkNode *pre_ptr = virtual_node;
LinkNode *work_ptr = virtual_node -> next;
int count = 0;
while(work_ptr){
if(count == index) {
pre_ptr -> next = new_node;
new_node -> next = work_ptr;
break;
}
work_ptr = work_ptr -> next;
pre_ptr = pre_ptr -> next;
++count;
}
++size;
}
void deleteAtIndex(int index) {
if (index < 0 || index >= size) return;
LinkNode *pre_ptr = virtual_node;
LinkNode *work_ptr = virtual_node -> next;
int count = 0;
while(work_ptr){
if(count == index) {
pre_ptr -> next = work_ptr -> next;
delete work_ptr;
break;
}
pre_ptr = pre_ptr -> next;
work_ptr = work_ptr -> next;
++count;
}
--size;
}
private:
int size;
LinkNode *virtual_node;
};
206
创建虚拟头结点,利用头插法构建原始链表的逆序链表
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode * virtual_head = new ListNode();
ListNode *work_ptr = head;
while(work_ptr) {
ListNode *temp = work_ptr -> next;
work_ptr -> next = virtual_head -> next;
virtual_head -> next = work_ptr;
work_ptr = temp;
}
return virtual_head->next;
}
};
24
利用虚拟头结点,统一对原始链表头结点的操作
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode *virtual_head = new ListNode();
virtual_head -> next = head;
ListNode *pre_ptr = virtual_head;
ListNode *work_ptr = head;
while(work_ptr && work_ptr -> next) {
// 更新过程要想清楚
ListNode *next_ptr = work_ptr -> next;
pre_ptr -> next = next_ptr;
work_ptr -> next = next_ptr -> next;
next_ptr -> next = work_ptr;
pre_ptr = work_ptr;
work_ptr = pre_ptr -> next;
}
return virtual_head -> next;
}
};
考虑:
当我们使用了虚拟头结点时,工作指针wokr_ptr从虚拟头结点开始较好,此时利用while遍历循环的条件是while(work_ptr -> next)
因为只有这样,才能确保第一次的work_ptr一定有效。
如果需要前后两个指针,则work_ptr需要指向work_ptr -> next ,此时while遍历循环的条件是while(work_ptr) ,因为原始链表可能为空
这段分析,可参考题目707的注释理解
|