代码随想录算法训练营第三天| 链表理论基础 203.移除链表元素 707.设计链表 206.反转链表
文章所有题目链接/文章讲解/视频讲解来源——代码随想录
链表理论基础
1. 链表是串联起来的,每个节点包含元素和指针
2. 链表包含单链表、双链表、循环链表
3. 链表里的节点不存储在连续空间,而是分散在存储中,用指针指向对应的元素
4. 链表中的操作包含增加、删除、查询,不适用于查询较多的题目
5. 定义链表:
struct ListNode{int val;ListNode* next;//自定义构造函数,如果不自定义则c++默认构造ListNode(int x) : val(x),next(NULL) {}
};//如果自定义构造函数,则初始化节点可直接赋值:ListNode* head=new ListNode(5);//如果使用默认的则不可直接赋值ListNode* head=new ListNode();head->val=5;
203.移除链表元素
建议: 本题最关键是要理解 虚拟头结点的使用技巧,这个对链表题目很重要。
一般代码题分析出怎么做了,就需要先看一下特殊情况,这个题是移除链表元素,那有可能移除头部的元素,这个情况是特殊的。
但是如果想要移动头指针所指向的元素,则需要将头指针后移,如果还需移除头结点则需要再移动,但这样与其余情况不形成统一,为了统一,我们设定一个虚拟头结点,用于需要删除头结点的情况。
当然也可以不设
这里只写设置虚拟头结点的代码:
/*** 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* vhead=new ListNode(0);//虚拟头结点vhead->next=head;//遍历链表ListNode* p=vhead;//遍历指针while(p->next!=NULL){if(p->next->val==val){//清理移除的元素ListNode* tmp = p->next;p->next=p->next->next;delete tmp;}else{p=p->next;}}head=vhead->next;delete vhead;return head;}
};
707.设计链表
包含初始化、查询、插入、追加、删除操作,我们可以分别实现:
初始化:
LinkedNode* vhead; // 虚拟头节点int size; // 链表大小MyLinkedList() {//初始化vhead=new LinkedNode(0);//直接初始化了size=0;};
在头部插入:
void addAtHead(int val) {//插到第一个元素之前LinkedNode* p = new LinkedNode(val);p->next = vhead->next;//这个为什么显示错误vhead->next=p;size++;}
在下标为index的前面插入
//将一个值为 val 的节点插入到链表中下标为 index 的节点之前void addAtIndex(int index, int val) {if (index > size || index < 0) { return;}LinkedNode* p = new LinkedNode(val);LinkedNode* q=vhead;for(int i = 0; i < index; i++) {q = q->next;}p->next = q->next;q->next = p;size++; }
在末尾插入
void addAtTail(int val) {//插到最后一个元素后LinkedNode* p = new LinkedNode(val);LinkedNode* q=vhead;while(q->next!=NULL){q=q->next;}q->next=p;size++; }
查询下标为index的val
int get(int index) {if (index > size - 1 || index < 0) {return -1;}LinkedNode* p=vhead->next;//指针int c=0;while(p!=NULL){if(c++==index){return p->val;}p=p->next;}return -1;}
删除下标为index前面的节点
void deleteAtIndex(int index) {if (index > size - 1 || index < 0) {return;}LinkedNode* q;q=vhead;// 需要找到要删除节点的前一个节点for(int i = 0; i < index; i++) {q = q->next;}LinkedNode* temp = q->next;q->next = q->next->next;delete temp;size--;}
单链表设计:
class MyLinkedList {
public://单链表struct LinkedNode {int val;LinkedNode* next;LinkedNode(int val):val(val), next(nullptr){}};LinkedNode* vhead; // 虚拟头节点int size; // 链表大小MyLinkedList() {//初始化vhead=new LinkedNode(0);//直接初始化了size=0;};int get(int index) {if (index > size - 1 || index < 0) {return -1;}LinkedNode* p=vhead->next;//指针int c=0;while(p!=NULL){if(c++==index){return p->val;}p=p->next;}return -1;}void addAtHead(int val) {//插到第一个元素之前LinkedNode* p = new LinkedNode(val);p->next = vhead->next;//这个为什么显示错误vhead->next=p;size++;}void addAtTail(int val) {//插到最后一个元素后LinkedNode* p = new LinkedNode(val);LinkedNode* q=vhead;while(q->next!=NULL){q=q->next;}q->next=p;size++;}//将一个值为 val 的节点插入到链表中下标为 index 的节点之前void addAtIndex(int index, int val) {if (index > size || index < 0) { return;}LinkedNode* p = new LinkedNode(val);LinkedNode* q=vhead;for(int i = 0; i < index; i++) {q = q->next;}p->next = q->next;q->next = p;size++;}void deleteAtIndex(int index) {if (index > size - 1 || index < 0) {return;}LinkedNode* q;q=vhead;// 需要找到要删除节点的前一个节点for(int i = 0; i < index; i++) {q = q->next;}LinkedNode* temp = q->next;q->next = q->next->next;delete temp;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.反转链表
这题可以用双指针和递归
这里先写双指针方法,由于如果再创建链表会浪费空间,不如就在原链表上进行,而这种操作其实很想数组中的双指针,拿过来用就行。
双指针:
/*** 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* t;ListNode* pre;ListNode* cur;pre=NULL;cur=head;while(cur!=NULL){t=cur->next;cur->next=pre;pre=cur;cur=t;}return pre;}
};
递归法:
实际上用到了一个函数:
return reverse(cur, temp);
表示递归地反转链表,是递归反转链表算法的核心部分。
就是不断交换
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(NULL, head);}
};