首页 > 编程语言 >代码随想录算法训练营第三天|203.移除链表元素,707.设计链表,206.反转链表

代码随想录算法训练营第三天|203.移除链表元素,707.设计链表,206.反转链表

时间:2024-09-28 22:01:13浏览次数:1  
标签:tmp head ListNode cur val 随想录 next 链表 移除

203.移除链表元素

文章链接:https://programmercarl.com/0203.移除链表元素.html#算法公开课
视频讲解:https://www.bilibili.com/video/BV18B4y1s7R9
题目出处:https://leetcode.cn/problems/remove-linked-list-elements/

卡哥在这里讲解了为什么要使用虚拟头节点,以及使用和不使用的区别,不清楚的话可以看视频讲解

  • 方一:直接删除头节点
    写的时候有几个小问题需要注意,已经在代码中标出
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        //不使用虚拟头节点,直接删除
        //删除头节点(头节点特殊,删除方式不一样,直接将head后移一个节点)
        while(head!=NULL&&head->val==val){ //这里一开始写的时候用的if,但是如果head后面的节点依然符合要求,则会漏掉这种情况
            ListNode* tmp=head;
            head=head->next;
            delete tmp;
        }
        //删除非头节点
        ListNode* cur=head;
        while(cur!=NULL&&cur->next!=NULL){   //这里一开始写的时候没有写cur!=NULL,这样是不行的,因为如果它为空了再操作会导致空指针错误
            if(cur->next->val==val){ 
                ListNode* tmp=cur->next;
                cur->next=cur->next->next;
                delete tmp;
            }
            else{
                cur=cur->next;
            }
        
        }
        return head;
    }
};
  • 方二:使用虚拟头节点
    错误如下图所示:

这里会报错的原因是 dummyHead 没有被初始化。dummyHead 是一个指向 ListNode 类型的指针,但没有给它分配内存空间。当前代码只声明了一个指针,但它指向的是未定义的内存区域,因此在访问 dummyHead->next 时会导致未定义行为或崩溃。
所以这里应该写成:

ListNode* dummyHead = new ListNode(0); //
dummyHead->next = head; 

总的代码如下所示:

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        //使用虚拟头节点
        ListNode* dummyHead=new ListNode(0); //注意将指针初始化
        dummyHead->next=head;
        ListNode* cur=dummyHead;
        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=dummyHead->next;
        return head;
    }
};
  • 方三:使用递归也很有意思
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        //使用递归
        if(head==nullptr){
            return nullptr;
        }
        
        if(head->val==val){
            ListNode* newHead=removeElements(head->next,val);
            delete head;
            return newHead;
        }
        else{
            head->next=removeElements(head->next,val); //这里一开始没有想到head->next
            return head;
        }
    }
};

707.设计链表

文章链接:https://programmercarl.com/0707.设计链表.html
视频链接:https://www.bilibili.com/video/BV1FU4y1X7WD
题目链接:https://leetcode.cn/problems/design-linked-list/description/

先构造节点,并为类写构造函数进行初始化。

class MyLinkedList {
public:
    //定义节点
    struct LinkNode{
        int val;
        LinkNode* next;
        LinkNode():next(nullptr){}//构造函数
        LinkNode(int val):val(val),next(nullptr){}//重载构造函数
    };
    MyLinkedList() { //构造函数
        dummyHead=new LinkNode();
        size=0;
    }
private:
    int size;
    LinkNode* dummyHead;
};

以下为学校内学到的写法:

  • 头插法:
void addAtHead(int val) {
        LinkNode* s=new LinkNode(val);
        s->next=dummyHead->next;
        dummyHead->next=s;
    }
  • 尾插法:
void addAtTail(int val) {
        LinkNode* s=new LinkNode(val);
        LinkNode* r=dummyHead;
        while(r->next!=NULL){
            r=r->next;
        }
        r->next=s;
        size++;
    }
  • 在index之前插入
void addAtIndex(int index, int val) {
        if(index>size||index<0){
            return;
        }
        LinkNode* cur=dummyHead;
        while(index--){
            cur=cur->next;
        }
        LinkNode* s=new LinkNode(val);
        s->next=cur->next;
        cur->next=s;
        size++;
    }
  • 获取第index个节点值
int get(int index) {
        if(index>(size-1)||index<0) return -1;
        LinkNode* cur=dummyHead->next;
        while(index--){
            cur=cur->next;
        }
        return cur->val;
    }
  • 删除第index个节点
void deleteAtIndex(int index) {
        if(index<0||index>=size) return;
        LinkNode* cur=dummyHead;
        while(index--){
            cur=cur->next;
        }
        LinkNode* tmp= cur->next;
        cur->next=cur->next->next;
        delete tmp;
        tmp=nullptr;//这里最好将其赋为空指针
        //delete命令指示释放了tmp指针原本所指的那部分内存,
        //被delete后的指针tmp的值(地址)并非就是NULL,而是随机值。也就是被delete后,
        //如果不再加上一句tmp=nullptr,tmp会成为乱指的野指针
        //如果之后的程序不小心使用了tmp,会指向难以预想的内存空间
        size--;
    }

206.反转链表

  • 双指针的写法:
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* cur=head;
        ListNode* pre=nullptr;
        while(cur!=NULL){
            ListNode* tmp=cur->next;
            cur->next=pre;
            pre=cur;
            cur=tmp;
        }
        return pre;
    }
};
  • 递归写法:
class Solution {
public:
    ListNode* reverse(ListNode* pre,ListNode*cur){
        // if(cur!=NULL){
        //     ListNode* tmp=cur->next;
        //     cur->next=pre;
        //     reverse(cur,tmp);
        // }
        // else return pre;
        if(cur==NULL) return pre;
        ListNode* tmp=cur->next;
        cur->next=pre;
        return reverse(cur,tmp);
    }
    ListNode* reverseList(ListNode* head) {
        ListNode* pre=nullptr;
        ListNode* cur=head;
        return reverse(pre,cur);
    }
};

第一次写,写成了注释掉的那部分,说明对递归还不太熟

标签:tmp,head,ListNode,cur,val,随想录,next,链表,移除
From: https://www.cnblogs.com/VickyWu/p/18438491

相关文章

  • 面试题 02.07. 链表相交
    明天回家喽,最近在学习的瓶颈期,感觉学的东西好难,有厌学的心理,但是我相信过了这段煎熬的时期,就好了。classSolution{public:ListNode*getIntersectionNode(ListNode*headA,ListNode*headB){intna=0,nb=0;ListNode*tempA=headA;L......
  • 链表分割 1.2版本
    现有一链表的头指针ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。思路:大致可以分为两个区域来存储数据:区域一存储小于36的节点,区域二存储大于36的节点.可以将这两个区域视为两个链表......
  • 算法训练营第三天| 203.移除链表元素、707.设计链表、206.反转链表
    203.移除链表元素状态:完成个人思路:首先令head符合条件,之后判断这个head是否为空,空的话返回空节点;非空的话继续进行。令pre=head;cur=head->next,只要cur非空,就判断cur的值的情况,如果需要删除,就改变pre->next和cur;如果不需要删除就继续检查下一个。看完讲解视频之后的想法:我......
  • 代码随想录算法训练营第三天 | 熟悉链表
    链表的存储方式数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。链表是通过指针域的指针链接在内存中各个节点。所以链表中的节点在内存中不是连续分布的,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。链表的定义template<typenameT>......
  • 代码随想录算法训练营第二天| 209.长度最小的子数组、59.螺旋矩阵II 、区间和、开发
    209.长度最小的子数组此题注重理解,同时我将res一开始初始化为sums的长度加一(因为不可能为此长度)INT32_MAX是一个常量,代表32位有符号整数的最大值classSolution{public:intminSubArrayLen(inttarget,vector<int>&nums){inti=0,j=0;//i为起始位置,j为......
  • 力扣 简单 206.反转链表
    文章目录题目介绍题解题目介绍题解法一:双指针在遍历链表时,将当前节点的next改为指向前一个节点。由于节点没有引用其前一个节点,因此必须事先存储其前一个节点。在更改引用之前,还需要存储后一个节点。最后返回新的头引用。代码如下:classSolution{public......
  • 力扣 中等 92.反转链表 II
    文章目录题目介绍题解题目介绍题解classSolution{publicListNodereverseBetween(ListNodehead,intleft,intright){//创建一个哑节点,它的next指向头节点,方便处理ListNodedummy=newListNode(0,head);//p0用于......
  • 算法题:用队列实现一个链表
    下面是添加了注释的ListNode类和LinkedListQueue类,以帮助理解每个部分的功能和目的://定义链表节点类,用于存储队列中的元素classListNode{intval;//存储节点的值ListNodenext;//指向下一个节点的指针//构造函数,用于创建新的节点ListNod......
  • 19. 删除链表的倒数第 N 个结点
    相当于删除正数第n个节点classSolution{public:ListNode*removeNthFromEnd(ListNode*head,intn){if(!head)returnhead;intlistLength=0;ListNode*temp=head;while(temp){temp=temp->next;......
  • 代码随想录训练营第44天|最长公共子序列
    1143.最长公共子序列classSolution{public:intlongestCommonSubsequence(stringtext1,stringtext2){text1.insert(text1.begin(),'');text2.insert(text2.begin(),'');intn1=text1.length(),n2=text2.length(),m......