代码随想录算法训练营第三天 | 203.移除链表元素、707.设计链表、206.反转链表
1 移除链表元素
注意
不要访问空指针
题目
解法
- 分情况处理解法
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
// 特殊处理头结点
while(head != nullptr && head->val == val){ // 顺序不能变,否则会报错,访问空指针中内容
ListNode* tmp = head;
head = head->next;
delete tmp;
}
ListNode* cur = head;
while(cur != NULL && cur->next != NULL ){
if(cur->next->val == val){
ListNode* tmp = cur->next;
cur->next =cur->next->next;
delete tmp;
}else{
cur = cur->next; // 不能是head,因为head是始终指向头部数据
}
}
return head;
}
};
2.虚拟头结点
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
// 虚拟头结点
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* cur = dummyHead;
while(cur != NULL && cur->next != NULL ){
if(cur->next->val == val){
ListNode* tmp = cur->next;
cur->next =cur->next->next;
delete tmp;
}else{
cur = cur->next;
}
}
head = dummyHead->next;
delete dummyHead;
return head;
}
};
基础知识补充
ListNode* cur = head 理解
这行代码做了以下事情:
类型声明:ListNode* 表示一个指向 ListNode 类型的指针。ListNode 通常是一个结构体或类,代表链表中的一个节点。这个结构体或类通常至少包含两个成员:一个存储数据的成员和一个指向下一个节点的指针成员。
变量声明:cur 是一个指针变量,它的类型是 ListNode*,即它可以存储一个指向 ListNode 类型对象的地址。
初始化:cur 被初始化为 head 的值。这里 head 应该是一个已经存在的 ListNode* 类型的变量,通常表示链表的头节点。换句话说,cur 现在指向与 head 相同的节点。
ListNode* dummyHead = new ListNode(0) 理解
这行代码做了以下事情:
类型声明:ListNode* 表示一个指向 ListNode 类型的指针。ListNode 通常是一个定义链表节点的结构体或类。
变量声明:dummyHead 是一个指针变量,它的类型是 ListNode*,即它可以存储一个指向 ListNode 类型对象的地址。
动态内存分配:new ListNode(0) 是在堆上动态地为一个 ListNode 对象分配内存,并调用其构造函数,传入参数 0。这意味着创建了一个新的 ListNode 对象,并将其初始化为包含值 0。
初始化:dummyHead 被初始化为新创建的 ListNode 对象的地址。
2 设计链表
题目
解法
- 虚拟头结点
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;
cout<<cur->val<<endl;
while(index--){
cur = cur->next;
}
cout<<cur->val<<endl;
return cur->val;
}
void addAtHead(int val) {
LinkedNode* newHead = new LinkedNode(val);
newHead->next = _dummyHead->next;
_dummyHead->next = newHead;
_size++;
}
void addAtTail(int val) {
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyHead; // 应该是等于虚拟头结点
while(cur->next){
cur = cur->next;
}
cur->next = newNode;
_size++;
}
void addAtIndex(int index, int val) {
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyHead;
if(index == _size ) {
addAtTail(val); // 里面已经有_size++,这里就不用写了
}else if(index < _size){ // 前提是 index >= 0
while(index--){
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
_size++;
}
}
void deleteAtIndex(int index) {
LinkedNode* cur = _dummyHead;
if(index <= _size -1){
while(index--){
cur = cur->next;
}
LinkedNode* temp = cur->next;
cur->next = cur->next->next;
delete temp;
_size--;
}
}
private:
int _size;
LinkedNode* _dummyHead;
};
3 反转链表
注意
注意顺序和头尾部位
题目
解法
- 双指针
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* temp;
ListNode* cur = head;
ListNode* pre = NULL;
while(cur){
temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
};
- 递归
class Solution {
public:
ListNode* reverse(ListNode* pre, ListNode* cur){
if(cur == NULL) return pre;
ListNode* temp = cur->next;
cur->next = pre;
pre = temp;
return reverse(cur, pre);
}
ListNode* reverseList(ListNode* head) {
return reverse(NULL,head );
}
};
4 感悟
C++ 基础不好,需要补一下
不亲自手动写一遍,永远也不知道哪里会出错,有时只是简单的顺序问题。
理解有些困难,需要多看看