当前位置: 首页 > backend >正文

代码随想录算法训练营第三天| 链表理论基础 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); 表示递归地反转链表,是递归反转链表算法的核心部分。

就是不断交换,

这个是通过pre=cur,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);}
};

http://www.xdnf.cn/news/20206.html

相关文章:

  • react antd mobile表单时间选择器
  • 系统架构思考20241204
  • 问卷系统测试报告
  • latex公式符号与字体
  • 【Lin通信】AUTOSAR架构下TC3xx芯片Lin报文收发详解
  • AI提示词增强丨用EARS语法进行产品原子化拆解
  • 【Redis】初识 Redis 与基础数据结构
  • 设置静态IP的方法
  • Docker跨架构部署实操第二弹
  • 代码改变生活:我用Python+LLM给自己写了个健身私教
  • 跨平台超低延迟RTSP播放器技术设计探究
  • EEMD-HHT算法
  • Android 权限机制默认授权分析
  • GPU版Pytorch的安装
  • 有鹿机器人的365天奇幻日记:我在景区当扫地僧
  • 如何通过 Gitee API 上传文件到指定仓库
  • go webrtc - 1 go基本概念
  • 鸿蒙Next的UI国际化与无障碍适老化实践:构建全球包容的数字世界
  • MySQL 综合练习
  • 【数据分享】上市公司数字化转型相关词频统计数据(2000-2024)
  • 解锁无限创意:Tldraw+cpolar如何通过内网穿透技术打破空间限制
  • 【leetcode】77.组合
  • DNS基本功能搭建
  • uni-app iOS 日志与崩溃分析全流程 多工具协作的实战指南
  • TCP/IP函数——sendmsg
  • 怎么获取Nano Banana的APK Key?
  • Dify基础应用
  • 1分钟了解等保测评流程
  • Kubernetes 全景指南:从核心概念到云原生未来
  • BYOFF(自定义格式函数)(79)