题1:
指路:LeetCode203 移除链表元素
思路及代码:
移除链表元素需要我们判断移除的元素是否是头节点,是则需要把头节点指向头节点的下一个节点,不是则让该元素节点的上一个节点指向该元素的下一个节点。显然,这里面有两种移除方法,代码过于冗余,我们尝试用统一的规则移除元素,也就是统一让元素节点的上一个节点指向该元素的下一个节点。也就是虚拟头节点法。虚拟头节点是在首元节点之前再定义一个头节点dummyhead,这样即使是删除首元节点也能用上面的统一规则。代码如下:
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
struct ListNode* dummyhead = new ListNode(0, head); // 在首元节点之前再加一个头节点
struct ListNode* temp = dummyhead; // 临时节点指向首元节点
while (temp->next != NULL) { // 首元节点不为零
if (temp->next->val == val) { // 头节点的下一个节点的值为指定删除的值,
temp->next = temp->next->next; // 删除这个节点
}
else {
temp = temp->next; // 否则节点后移
}
}
return dummyhead->next; // 而不是head节点因为有可能head节点会被删除
}
};
题2:
指路:LeetCode707 设计链表
思路与代码:
链表文化博大精深,这里我们先用单链表模仿操作,后续深度剖析。
class MyLinkedList {
public:
struct LinkedNode {
int val;
LinkedNode* next;
LinkedNode(int val) : val(val), next(nullptr){}
};
MyLinkedList() {
_dummyhead = new LinkedNode(0);
_size = 0;
}
int get(int index) {
if (index > (_size - 1) || index < 0)
return-1;
LinkedNode* cur = _dummyhead->next;
while(index--) {
cur = cur->next;
}
return cur->val;
}
void addAtHead(int val) {
LinkedNode* cur = new LinkedNode(val);
cur->next = _dummyhead->next;
_dummyhead->next = cur;
_size++;
}
void addAtTail(int val) {
LinkedNode* cur = new LinkedNode(val);
LinkedNode* temp = _dummyhead;
while(temp->next != nullptr) {
temp = temp->next;
}
temp->next = cur;
_size++;
}
void addAtIndex(int index, int val) {
if (index > _size) return ;
if (index < 0) index = 0; // 判断合法化
LinkedNode* temp = new LinkedNode(val);
LinkedNode* cur = _dummyhead;
while (index--)
cur = cur->next;
temp->next = cur->next;
cur->next = temp;
_size++;
}
void deleteAtIndex(int index) {
if (index >= _size || index < 0) // 不合法
return ;
LinkedNode* cur = _dummyhead;
while (index--) {
cur = cur->next;
}
LinkedNode* temp = cur->next;
cur->next = cur->next->next;
delete temp; // C++手动删内存
temp = nullptr;
_size--;
}
void printLinkedList() {
LinkedNode* cur = _dummyhead;
while (cur->next != nullptr) {
cout << cur->next->val << " ";
cur = cur->next;
}
cout << endl;
}
private:
int _size;
LinkedNode* _dummyhead;
};
题3:
指路:LeetCode206 反转链表
思路与代码:
双指针法。定义一个cur指针使其指向头节点,再定义一个pre指针使其指向头节点的上一个节点,因为头节点的上一个节点处没有值,所以将pre指针初始化为NULL。继续定义一个临时指针temp,在后面让它指向cur的下一个节点。也就是:
pre | cur | cur->next |
其中,temp指向cur->next;在接下来的反转过程中,我们只需要将cur->next指向pre,让pre指向cur,再将cur指向temp,也就是:
cur | temp | pre |
当cur指向NULL时最后返回pre即可。代码如下:
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* cur = head;
ListNode* temp = new ListNode(0, head); // 定义一个临时指针
ListNode* pre = NULL; // 为了让它指向head前一位
while (cur) {
temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
};