LeetCode刷题笔记【3】:链表专题-1(移除链表元素,设计链表,反转链表)

前置知识

链表基础知识

链表分为单链表、双链表、循环链表。

不同于数组,在内存中连续分布,链表的节点是不连续分布的,通过指针串联在一起。

C++中定义链表的方式

需要熟练掌握默写,虽然在LeetCode模式下ListNode一般是写好的,但是在acm模式下大概率需要自己写。

struct ListNode{
	int val;
	ListNode* next;
	ListNode() : val(0), next(NULL) {}
	ListNode(int x) : val(x), next(NULL) {}
	ListNode(int x, ListNode* node) : val(x), next(node) {}
};

如果不写这个构造函数的话,C++会自动有一个构造函数,但是就不能在新建节点的时候直接传参进去了,不是很方便。

链表的操作

注意:操作链表很多时候都需要着眼于其前置节点;
所以通常会设置一个dummyHead(虚假头结点)。

删除节点

下图删除D节点。
在这里插入图片描述
虽然操作上修改C的next指向就行,但是C++没有内存回收机制,所以最好还是删除D。
这就需要保留一个指向D的指针,然后:

delete D;

添加节点

在这里插入图片描述

和数组对比

在这里插入图片描述
注意:虽然链表的删除和添加本身都是O(1),但是找到对应需要删除的节点、找到插入节点的位置,是O(n)的。

参考文章:关于链表,你该了解这些!

203. 移除链表元素

题目描述

在这里插入图片描述

LeetCode链接:https://leetcode.cn/problems/remove-linked-list-elements/description/

解题思路

如果头结点本身也要被删除,可能会比较麻烦。
所以为了统一操作方式,最好设置一个dummyHead。

代码

lass Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* newHead = new ListNode(0, head);
        ListNode* cur = newHead;
        while(cur->next != NULL){
            if(cur->next->val == val){
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;
                continue;
            }
            cur = cur->next;
        }
        return newHead->next;
    }
};

707. 设计链表

题目描述

在这里插入图片描述
在这里插入图片描述

LeetCode链接:https://leetcode.cn/problems/design-linked-list/

解题思路

一些注意的点:
设置一个dummyHead更方便;
涉及到index的地方,开头先判断一下,如果index太小太大都不行,但是index是>=还是>size的时候不行, 就要看当时的情况;
记得要在添加和删除节点后++ --size;
get要定位当前节点, delete和addAtIndex要定位前置节点.

代码

class MyLinkedList {
public:
    struct LinkNode{
        int val;
        LinkNode* next;
        LinkNode() : val(0), next(NULL){}
        LinkNode(int x) : val(x), next(NULL){}
        LinkNode(int x, LinkNode* node) : val(x), next(node){}
    };

    MyLinkedList() {
        size=0;
        dummyHead = new LinkNode();
    }
    
    int get(int index) {
        if(index<0 || index>=size)
            return -1;
        LinkNode* cur = dummyHead;
        for(int i=0; i<=index; i++){
            cur = cur->next;
        }
        return cur->val;
    }
    
    void addAtHead(int val) {
        LinkNode* node = new LinkNode(val, dummyHead->next);
        dummyHead->next = node;
        size++;
        return;
    }
    
    void addAtTail(int val) {
        LinkNode* tail = dummyHead;
        LinkNode* node = new LinkNode(val);
        while(tail->next != NULL){
            tail = tail->next;
        }
        tail->next = node;
        size++;
        return;
    }
    
    void addAtIndex(int index, int val) {
        if(index<0 || index>size)
            return;
        LinkNode* cur = dummyHead;
        for(int i=0; i<index; ++i){
            cur = cur->next;
        }
        LinkNode* node = new LinkNode(val);
        node->next = cur->next;
        cur->next = node;
        size++;
        return;
    }
    
    void deleteAtIndex(int index) {
        if(index<0 || index>=size)
            return;
        LinkNode* cur = dummyHead;
        for(int i=0; i<index; ++i){
            cur = cur->next;
        }
        LinkNode* tmp = cur->next;
        cur->next = cur->next->next;
        delete tmp;
        tmp = NULL;
        size--;
        return;
    }
private:
    int size;
    LinkNode* dummyHead;
};

206. 反转链表

题目描述

在这里插入图片描述

LeetCode链接:https://leetcode.cn/problems/reverse-linked-list/

解题思路

可以遍历的过程中不断新建一个链表, 但是这就很复杂;
最好的方式是遍历一遍, 过程中修改指针指向, 然后返回原尾节点(新头节点);
这就需要三个指针(如下图)
在这里插入图片描述
prev记录前置节点;
cur记录当前节点;
next记录后继节点(图中没有表现出来, 但是cur之所以能在cur->next改变后依然能移动, 就是以为next的存在).

代码

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head==NULL)
            return head;
        ListNode* cur=head;
        ListNode* prev = NULL;
        ListNode* next = NULL;
        while(cur){
            next = cur->next;
            cur->next = prev;//这里很巧妙地让最初head的next变为NULL, 不用单独拎出来处理了
            prev = cur;
            cur = next;
        }
        return prev;
    }
};

总结

链表的操作要特别注意next的指向, 以及循环的边界;
dummyHead的使用也需要很熟练;

链表可以说是很多操作的基础, 所以链表的添加, 删除, 反转等操作应该非常熟练才行.

本文参考:
203.移除链表元素
707.设计链表
206.反转链表

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值