刷穿leetcode之链表总结(1)

最近感觉自己的算法能力太拉了,所以想提升一下自己的算法能力,刷刷leetcode,总结总结。最开始总结的是链表,链表是数据结构十分基础的一个概念,它的类型有几种,分别是单链表,双链表,环形链表。
单链表:
单链表
双链表:
双链表
环形链表:
环形链表
上述是分别是单链表,双链表,环形链表的介绍,为什么会有链表这种概念呢,它有什么特点呢?那要介绍一下跟它比较类似的一种存储结构,线性表(数组),数组的存储方式都是一段线性内存的存储,如果要对数组进行添加元素什么的,非常麻烦!但是链表其在内存中不是线性存储的,而是乱序存储的,只需要在每个节点中将附近的节点的地址存储在其相应的指针域。本篇文章的重点是介绍单链表的经典问题
我个人认为单链表中最关键的操作就是删除某个节点,有几种考法:
1.删除链表等于某个值的操作:
Leetcode203.移除链表元素
最开始拿到这道题目的时候,第一思路就是使用while循环遍历链表,在循环中判断该节点的值是否等于val,但是这个时候发现没有区分头节点就是要删除的节点,故把头节点就是要删除的节点这种情况单独拿出来讨论。

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* cur=head;
        while (cur != NULL && cur->val == val) 
        { 
            ListNode* tmp = cur;
            cur = cur->next;
            delete tmp;
        }
        while(cur!=nullptr&&cur->next!=nullptr)
        {
            if(cur->next->val==val)
            {
                ListNode* temp=cur->next;
                cur->next=cur->next->next;
                delete temp;
            }
            else
            {
                cur=cur->next;
            }
        }
        return head;
    }
};

最开始写出来的是这个代码,然后报错了。
报错信息
开始我没有画图,单纯的想,想不明白。后面我画了一个图,把这个问题这个解决了(所以我觉得做链表的题目,做不出来的时候,一定要画图!!)
我们就用leetcode的[7777]那个例子举例:

从这个图就可以看出来,我的代码head指向的头节点(为要删除的元素),那么cur去删除了之后,head就会指向空了,head这个指针就会变成悬浮指针。(我做完经典几道指针,我感觉掌握这个思维特别重要,特别是写链表删除操作的时候)。
那么修改一下上面的代码:

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        //暴力法
        //区分头节点是否等于val
        //等于val的时
        while(head!=nullptr&&head->val==val)
        {
            ListNode* tmp=head;
            head=head->next;
            delete tmp;
        }
        //不等于val的时候
        ListNode* cur=head;
        while(cur!=nullptr&&cur->next!=nullptr)
        {
            if(cur->next->val==val)
            {
                ListNode* tmp=cur->next;
                cur->next=cur->next->next;
                delete tmp;
            }
            else
            {
                cur=cur->next;
            }
        }
        return head;
    }
};

这样子就是正确的了,所以对于链表问题关注头节点是否指空是一件非常重要的事情。当然除了这种修改的方法,还有一个更加普遍的做法,就是增加一个虚假头节点(这种做法常常都是用来防止head头指针变成悬浮指针!)
第二种做法:对于链表问题,创建一个虚假头节点十分关键ListNode* DummyNode=new ListNode(0)
那么在使用虚假头节点这种做法的时候,又会不会遇到上面那种问题呢?来看这段代码:

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* dummyhead=new ListNode(0);
        dummyhead->next=head;
        ListNode* cur=dummyhead->next;
        while(cur!=nullptr&&cur->next!=nullptr)
        {
            if(cur->val==val)
            {
                ListNode* temp=cur;
                cur=cur->next;
                delete temp;
            }
            else
            {
                cur=cur->next;
            }
        }
        head=dummyhead->next;
        return head;
    }
};

又出现了这个问题,有了上次经验,我们直接画图!
报错信息

创建虚假头节点的目的,始终保持链表的连接,dummyhead这个虚假头节点是始终连在链表里面的,但是这样写又把dummyhead->next 变成空呢!又断连了,所以又出现了上述的问题。修改一下代码:

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* DummyNode=new ListNode(0);
        DummyNode->next=head;
        ListNode* cur=DummyNode;
        while(cur->next!=nullptr)
        {
            if(cur->next->val==val)
            {
                ListNode* temp=cur->next;
                cur->next=cur->next->next;
                delete temp;
            }
            else
            {
                cur=cur->next;
            }
        }
        head=DummyNode->next;
        delete DummyNode;
        return head;
    }
};

画一下图说明为什么修改后的代码又是可以的呢?
所以对于链表而言,很多设置都是很有意义的,值得深入揣摩的!同样的题目还有
707. 设计链表19. 删除链表的倒数第 N 个结点 后面的博客接着更新!
最后,引用leetcode上面的一位老哥的话:“像我这样优秀的人,本该灿烂过一生,怎么多年力扣到头来,还在链表里浮沉!”送给大家,同时也祝大家元旦快乐!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值