这是跟Carl学习《代码随想录》的第三天,主要开始练习链表的操作,之前这种数据结构用的比较少,可能会相对困难一点,今天主要是如何创建链表以及如何实现链表的增删改查。
注意:链表的基础操作还是非常重要的,后续需要重点练习。
今日任务
链表理论基础
203.移除链表元素
707.设计链表
206.反转链表
一、 链表理论基础
建议: 了解一下链接基础,以及链表和数组的区别
文章链接: https://programmercarl.com/%E9%93%BE%E8%A1%A8%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html
主要掌握如何创建一个链表的结构体,在Leetcode中一般都会默认生成好:
// 单链表
struct ListNode {
int val; // 节点上存储的元素
ListNode *next; // 指向下一个节点的指针
ListNode(int x) : val(x), next(NULL) {} // 节点的构造函数
};
二、 203.移除链表元素
建议: 本题最关键是要理解 虚拟头结点的使用技巧,这个对链表题目很重要。
Leetcode题目:203.移除链表元素
题目链接/文章讲解/视频讲解: https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html
本题较为简单,主要学习如何删除节点:
有以下注意事项:
(1)不可以使用头结点指针进行遍历,需要新创建一个遍历指针,通常定义为cur;
(2)结束的时候需要重新定义回头指针,即head = dummyNode -> next;
/**
* 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* removeElements(ListNode* head, int val) {
ListNode *dummyNode = new ListNode();
dummyNode -> next = head;
ListNode *cur = dummyNode;
while(cur->next != NULL){
if(cur->next->val == val){
ListNode *tmp = cur -> next;
cur->next = cur->next->next;
delete tmp;
}else{
cur = cur->next;
}
}
head = dummyNode -> next;
delete dummyNode;
return head;
}
};
三、707.设计链表
建议: 这是一道考察 链表综合操作的题目,不算容易,可以练一练 使用虚拟头结点
LeetCode题目:707.设计链表
题目链接/文章讲解/视频讲解: https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html
本题主要实现链表的增删改查,而且要注意索引是从0 开始的,然后类中的成员变量为虚拟头结点和链表的数量大小。然后在插入某一个节点时,要先把后面的搭好,然后再搭前面的。
class MyLinkedList {
public:
// 定义链表结构体
struct LinkNode{
int val;
LinkNode * next;
LinkNode(int x): val(x), next(nullptr){}
};
MyLinkedList() {
dummyNode = new LinkNode(0);
size = 0;
}
int get(int index) {
LinkNode *cur = dummyNode -> next;
if(index < 0 || index > size - 1){
return -1;
}else{
while(index--){
cur = cur -> next;
}
return cur->val;
}
}
void addAtHead(int val) {
LinkNode *headNode = new LinkNode(val);
headNode -> next = dummyNode -> next;
dummyNode -> next = headNode;
size++;
}
void addAtTail(int val) {
LinkNode *tailNode = new LinkNode(val);
LinkNode *cur = dummyNode;
while(cur -> next != nullptr){
cur = cur->next;
}
cur -> next = tailNode;
size++;
}
void addAtIndex(int index, int val) {
if(index > size) return;
if(index < 0) index = 0;
LinkNode *newNode = new LinkNode(val);
LinkNode* cur = dummyNode;
while(index--){
cur = cur->next;
}
newNode -> next = cur -> next;
cur -> next = newNode;
size++;
}
void deleteAtIndex(int index) {
if(index < 0 || index >= size){
return;
}
LinkNode *cur = dummyNode;
LinkNode *tmp;
while(index--){
cur = cur -> next;
}
tmp = cur -> next;
cur -> next = cur->next->next;
delete tmp;
tmp = nullptr;
size--;
}
private:
LinkNode *dummyNode;
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);
*/
四、206.反转链表
建议先看视频讲解,视频讲解中对 反转链表需要注意的点讲的很清晰了,看完之后大家的疑惑基本都解决了。
Leetcode题目:206.反转链表
题目链接/文章讲解/视频讲解: https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html
解决思路双指针法:
/**
* 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, *cur, *temp;
pre = NULL;
cur = head;
while(cur != NULL){
temp = cur -> next;
cur -> next = pre;
pre = cur;
cur = temp;
}
return pre;
}
};