203.移除链表元素
要点:加入一个虚拟头节点会省心很多
方法:
假设 A -> B -> C 三个节点,B是要删除的节点,B删除后,A->next就变为C
所以要删除一个节点,要关注三个节点,被删除的B,B前面的A,B后面的C
A:需要修改next指针
B:需要delete释放空间
C:需要暂时用变量保存一下,方便A指向
如果从虚拟头节点开始遍历,遍历到底C为nullptr
A - cur B - cur->next C - cur->next->next
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* temp_head = new ListNode(0);
temp_head->next = head;
ListNode* cur = temp_head;
while (cur->next != nullptr) {
if (cur->next->val == val) {
ListNode* del_node = cur->next;
cur->next = cur->next->next;
delete del_node;
} else {
cur = cur->next;
}
}
head = temp_head->next;
delete temp_head;
return head;
}
};
707.设计链表
要点:如果要学链表的话,必然需要学自定义一个链表,包括链表的增删改查操作
题目中是查增(头、尾、指定index)删(指定index)
改的操作与查类似,查出来后修改节点的val即可
同样也是需要关注要操作节点的前后节点,有虚拟头节点会舒服很多
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* newNode = new LinkedNode(val);
newNode->next = _dummyHead->next;
_dummyHead->next = newNode;
_size++;
}
void addAtTail(int val) {
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyHead;
while (cur->next != nullptr) {
cur = cur->next;
}
cur->next = newNode;
_size++;
}
void addAtIndex(int index, int val) {
if (index > _size) return;
if (index < 0) index = 0;
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyHead;
while(index--) {
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
_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 = temp->next;
delete temp;
temp = nullptr;
_size--;
}
private:
int _size;
LinkedNode* _dummyHead;
};
206.反转链表
要点:改变整个链表的指针方向,即全部朝后的,反转成全部朝前的,头上加个nullptr,尾巴的nullptr不要
看懂双指针和递归的原理后,记住先保存,再转向,再移动,就不会出错
方法:
需要两个指针,pre和cur
pre初始化为nullptr,插在原链表的头上,开始遍历
1. 保存 temp = cur->next;
2. 转向 cur-next = pre;(本来pre是指向cur的,反转成cur指向pre)
3. 移动 pre = cur; cur = temp;
遍历到最后,pre就是反转后链表的头节点,cur为nullptr
class Solution {
public:
ListNode* reverse(ListNode* pre, ListNode* cur) {
if (cur == NULL)
return pre;
ListNode* temp = cur->next;
cur->next = pre;
return reverse(cur, temp);
}
ListNode* reverseList(ListNode* head) { return reverse(nullptr, head); }
};