203.移除链表元素
要点
- 删除某个节点,
cur指针指在其前一个节点。每次处理的是cur->next这个节点 - 有虚拟头节点,统一了头节点、非头节点的删除逻辑
虚拟头节点写法
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* fakeHead = new ListNode(0, head);
ListNode* cur = fakeHead;
while (cur->next != nullptr){
if (cur->next->val == val){
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}else{
cur = cur->next;
}
}
head = fakeHead->next;
delete fakeHead;
return head;
}
};
总结
移除链表元素中被移除的元素需要释放其空间,在cpp中为delete tmp;,free了那部分空间。
707.设计链表
要点
- 结构体也属于类的一个属性,结构体也能有类似构造函数的
--、++操作能并在一些赋值、条件判断语句的,就不要另起一行
带虚拟头节点写法
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 < 0 || index > (_size - 1)) {
return -1;
}else {
LinkedNode* cur = _dummyHead->next;
while (index) {
cur = cur->next;
index--;
}
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* cur = _dummyHead;
int size = _size;
while (size) {
cur = cur->next;
size--;
}
LinkedNode* newNode = new LinkedNode(val);
cur->next = newNode;
_size++;
}
//index == _size的情况包含在 在任意位置前插入新元素 中了
void addAtIndex(int index, int val) {
if (index < 0 || index > _size) {
return;
}
LinkedNode* cur = _dummyHead;
while (index) {
cur = cur->next;
index--;
}
LinkedNode* newNode = new LinkedNode(val);
newNode->next = cur->next;
cur->next = newNode;
_size++;
}
void deleteAtIndex(int index) {
if (index < 0 || index >= _size) {
return;
}
LinkedNode* cur = _dummyHead;
LinkedNode* tmp;
while (index) {
cur = cur->next;
index--;
}
tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
_size--;
}
private:
LinkedNode* _dummyHead;
int _size;
};
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList* obj = new MyLinkedList();
* int param_1 = obj->get(index);
* obj->addAtHead(val);
* obj->addAtTail(val);
* obj->addAtIndex(index,val);
* obj->deleteAtIndex(index);
*/
总结
get、add、delete链表的增删查操作,MyLinkedList* obj = new MyLinkedList();初始化一个实例,按照构造方法定义的方式给类的属性赋值。
206.反转链表
要点
- 双指针法依次定义
pre cur tmp,其中修改指针指向是pre cur之间操作的,tmp用来连贯 - 在每轮修改指针时,因为一旦修改了,
cur往后的节点就断了,所以在修改前先更新tmp指针 -
- 记录
tmp; 2. 修改指针; 3. 后移到下一个更改位置;
- 记录
双指针法
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre = nullptr;
ListNode* cur = head;
ListNode* tmp;
//在修改指针前,更新tmp
while (cur) {
//1.
tmp = cur -> next;
//2.
cur -> next = pre;
//3.
pre = cur;
cur = tmp;
}
return pre;
}
};
总结
反转链表双指针法包含 初始化、一轮轮的修改指针、当cur == null时返回pre 三个阶段。
中间的修改过程是相同的子问题,可写成递归的形式。