随想录Day3|203. 移除链表元素、707. 设计链表、206. 反转链表

发布时间 2023-09-23 00:20:41作者: Alouette29

随想录Day3|203. 移除链表元素、707. 设计链表、206. 反转链表

 

之后的文章就不放题目链接了,因为真的很推荐Vscode的LeetCode插件,搜一下题号就可以开始code了!

我没怎么用过C++所以也是才开始熟悉它的特性,因为是链表的开始,所以搬运一下卡尔的这一小段代码。

// 单链表
struct ListNode {
    int val;  // 节点上存储的元素
    ListNode *next;  // 指向下一个节点的指针
    ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
};
ListNode* head = new ListNode(5);

自己定义了构造函数就可以直接传入要赋的值使用,比C++默认生成的构造函数方便一些。

 

203. 移除链表元素

文章讲解

视频讲解

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回新的头节点

  • 列表中的节点数目在范围 [0, 104]
  • 1 <= Node.val <= 50
  • 0 <= val <= 50

 

第一想法

需要特殊考虑如果要删除头节点。最坏的情况就是如果val是1,这个链表前面一串都是1,则记录头节点变化会很繁琐,删除头节点重穿链表也会很繁琐。

所以采用dummy_head作为不变的头节点,紧接着它之后的才是真·头节点。这里的dummy_head就是纯粹只起到一个结构的作用,后面的都是有记录值的节点。

 

用时12min~

ListNode *removeElements(ListNode *head, int val)
{
    ListNode *dummy_head = new ListNode(0, head);
    ListNode *pre = dummy_head;
    ListNode *cur = head;
    while (cur)
    {
        if (cur->val == val)
        {
            ListNode *tmp = cur;
            pre->next = cur->next; // 重新连接链表
            cur = cur->next;
            delete tmp; // 删除该节点
        }
        else
        {
            pre = cur;
            cur = cur->next;
        }
    }
    head = dummy_head->next;
    delete dummy_head;
    return head;
}

 

707. 设计链表

文章讲解

视频讲解

题目略长,总之就是写函数实现需要初始化、读取值、插入、头插、尾插、特定index插、删除,这些基本操作。

 

第一想法

要注意判断给定的index是否有效,那最好在初始化对象的时候就添加一个链表长度的属性,比较方便。以及最开头写的这一小段就可以用上了!

因为不太熟悉C++面向对象的语法,看卡尔的题解稍微纠结久了点,这个private定义数据类型的写法是第一次见哎。

 

用时32min~

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

    MyLinkedList() // 没看到数据类型对吧,别急
    {
        _dummyHead = new ListNode(0);
        _size = 0;
    }

    int get(int index)
    {
        if (index >= _size || index < 0)
            return -1;
        ListNode *cur = _dummyHead->next;
        while (index--)
            cur = cur->next;
        return cur->val;
    }

    void addAtHead(int val)
    {
        ListNode *node = new ListNode(val);
        node->next = _dummyHead->next;
        _dummyHead->next = node;
        _size++;
    }

    void addAtTail(int val)
    {
        ListNode *node = new ListNode(val);
        ListNode *cur = _dummyHead;
        while (cur->next)
            cur = cur->next;
        cur->next = node;
        _size++;
    }

    void addAtIndex(int index, int val)
    {
        if (index > _size)
            return;
        if (index < 0)
            index = 0;
        ListNode *node = new ListNode(val);
        ListNode *cur = _dummyHead;
        while (index--)
            cur = cur->next;
        node->next = cur->next;
        cur->next = node;
        _size++;
    }

    void deleteAtIndex(int index)
    {
        if (index >= _size || index < 0)
            return;
        ListNode *cur = _dummyHead;
        while (index--)
            cur = cur->next;
        ListNode *tmp = cur->next;
        cur->next = tmp->next;
        delete tmp;
        tmp = nullptr;
        _size--;
    }

private: // 没错数据类型是在这儿定义的!
    int _size;
    ListNode *_dummyHead;
};

在private部分才写数据类型是为了封装,只有在类中才能访问_dummyHead_size

 

206. 反转链表

文章讲解

视频讲解

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

 

第一想法

用一个pre指针,一个cur指针,每次cur->next指向pre就实现了反转。要尤其注意在要改变一个指针之前把它的原值保存下来(如果还要用),也要注意操作的顺序,比如需要首先pre = cur再去改变cur的值,也就是cur = tmp,这里tmp记录的是原来的链表中cur的下一个。

 

看完随想录题解的想法

啊啊啊我第一次遇到这么长的报错,忘保存了总之巨大一串,然后才发现只有前两行有问题,我分别赋值为headhead->next了,这显然不对,因为pre的初值就是反转后链表的最末端,一定要以nullptr结尾。所以应该分别是nullptrhead

 

用时13min~

ListNode *reverseList(ListNode *head)
{
    ListNode *pre = nullptr;
    ListNode *cur = head;
    ListNode *tmp;
    while (cur)
    {
        tmp = cur->next;
        cur->next = pre;
        pre = cur;
        cur = tmp;
    }
    // 最后cur是nullptr,pre是新的头节点
    return pre;
}

 

碎碎念

为什么每天都是凌晨写完啊hhh明天一定要优化一下时间段!不过还好这次是链表的初级,用时不太久。

真好,一般在十点半如果没有一个硬性约束我一定不会愿意开始一个新的工作项,不过这可是要打卡的!