代码随想录算法训练营第三天 c++实现 | LeetCode203. 移除链表元素、LeetCode707. 设计链表、LeetCode206. 反转链表

本文介绍了使用C++解决LeetCode中的三个链表问题:203.移除链表元素,采用了前缀节点处理头节点删除;707.设计链表,实现了链表的基本操作如头插、尾插等;206.反转链表,利用双指针完成链表反转。每个问题都分析了时间复杂度和空间复杂度,并提供了相应的代码实现。
摘要由CSDN通过智能技术生成

代码随想录算法训练营第三天 c++实现 | LeetCode203. 移除链表元素、LeetCode707. 设计链表、LeetCode206. 反转链表

203. 移除链表元素

题目链接:203. 移除链表元素

思路:

  • 删除链表中的元素,其实只需要将其前一个节点的指针指向被删除元素的下一个节点即可
  • 但是在代码实现中有一些需要考虑
    1. 如果需要删除的元素为链表第一个节点,直接删除会丢失头指针,这里使用一个前缀节点指向链表的第一个节点,删除的时候改变前缀节点的指针即可。返回的时候也返回前缀节点指针。
    2. 为了便于理解和代码逻辑清楚,使用前后两个指针指向。后者指向当前比较值的节点,前者指向后者的前一个节点。
    3. 为避免内存泄漏,对删除的节点释放内存,释放前先用临时指针标志位置
    4. 前缀节点也会形成内存泄漏,所以用直接构造对象的方式创建

时间复杂度:O(n),空间复杂度O(1)

代码:

class Solution
{
public:
    ListNode *removeElements(ListNode *head, int val)
    {
        // 创建前缀节点对象,离开作用域自动释放内存 
        ListNode pre; 
        // 前缀节点指针指向头节点
        pre.next = head;
        ListNode *front = ⪯
        ListNode *back = head;
        while(back != nullptr)
        {
            if (back->val==val)
            {
                ListNode * temp = back;
                back = back->next;
                front->next = back;
                delete temp;
            }
            else
            {
                front = back;
                back = back->next;
            }
            
        }
        // 返回前缀节点的指针
        return pre.next;
    }
};

总结:

  • 前缀节点的思想在链表这些题目中挺常见,(嘿嘿)这个思想在看别人代码之前自己有悟了出来,后来看carl哥的文章补充上了内存释放,这次做的还是很快的
  • 做题体验:哈哈哈哈 > 嘿嘿 > 哎哎 > 嘤嘤
  • 时间:10min
  • 三刷

707. 设计链表

题目链接:707. 设计链表

思路:

  • 这里也用到了前缀节点的思想,MyLinkedList *obj = new MyLinkedList();的时候返回的是指向前缀节点的指针
  • 成员变量:valnext自己写一下
  • 成员函数:由易到难来讲吧
  1. MyLinkedList() : 构造函数的时候指针赋nullptr,值随意
  2. void addAtHead(int val):开辟内存构造新节点,新节点指针指向原先第一个节点,前缀节点指针指向新节点
  3. void addAtTail(int val):从前缀节点开始遍历,遇到next指向nullptr时指向新节点即可
  4. int get(int index):从0开始计数遍历,计数等于索引的时候返回值,指针为空时退出。无效索引都会退出,返回-1即可
  5. void addAtIndex(int index, int val):index<=0的情况下直接头插;接下来的操作和索引查询类似
  6. void deleteAtIndex(int index):把遍历查询的思路和移除节点那一题结合一下就行

时间复杂度:O(n),遍历链表

空间复杂度O(n),开辟链表空间?

代码:

class MyLinkedList
{

    friend void printList(MyLinkedList *mll);

public:
    MyLinkedList()
    {
        next = nullptr;
        val = 0;
    }

    int get(int index)
    {
        int count = 0;
        MyLinkedList *p = this;
        while (p->next != nullptr)
        {
            if (count == index)
            {
                return p->next->val;
            }
            else
            {
                p = p->next;
                ++count;
            }
        }
        return -1;
    }

    void addAtHead(int val)
    {
        MyLinkedList *newOne = new MyLinkedList();
        newOne->val = val;
        newOne->next = this->next;
        this->next = newOne;
    }

    void addAtTail(int val)
    {
        MyLinkedList *p = this;
        while (p->next != nullptr)
        {
            p = p->next;
        }
        MyLinkedList *newOne = new MyLinkedList();
        newOne->val = val;
        p->next = newOne;
    }

    void addAtIndex(int index, int val)
    {
        if (index <= 0)
        {
            MyLinkedList *newOne = new MyLinkedList();
            newOne->val = val;
            newOne->next = this->next;
            this->next = newOne;
        }
        else
        {
            int count = 0;
            MyLinkedList *p = this;
            while (p != nullptr)
            {
                if (count == index)
                {
                    MyLinkedList *newOne = new MyLinkedList();
                    newOne->val = val;
                    newOne->next = p->next;
                    p->next = newOne;
                    break;
                }
                else
                {
                    p = p->next;
                    ++count;
                }
            }
        }
    }

    void deleteAtIndex(int index)
    {
        int count = 0;
        MyLinkedList *p = this;
        while (p->next != nullptr)
        {
            if (count == index)
            {
                MyLinkedList *tmp = p->next;
                p->next = tmp->next;
                delete tmp;
                break;
            }
            else
            {
                p = p->next;
                ++count;
            }
        }
    }

private:
    int val;
    MyLinkedList *next;
};

总结:

  • 自己一刷的时候做了很久,不过也是一遍过了,二刷熟悉多了。carl哥的解法好像和我不太一样,他还定义了一个结构体?以后看看吧[TODO],我觉得我这种把结构和方法定义在一起的思路也挺好嘿嘿
  • 做题体验:哈哈哈哈 > 嘿嘿 > 哎哎 > 嘤嘤
  • 时间:40min
  • 二刷

206. 反转链表

题目链接:206. 反转链表

思路:

  • 双指针思路;注意前侧指针的初始值应该为空

时间复杂度:O(n),空间复杂度O(1)

代码:

class Solution
{
public:
    ListNode *reverseList(ListNode *head)
    {
        ListNode *front = nullptr;
        ListNode *back = head;
        while (back != nullptr)
        {
            // 临时指针指向下一个节点
            ListNode *tmp = back->next;
            // 当前节点指针指向前任节点
            back->next = front;
            // 前任节点指针指向当前节点
            front = back;
            // 当前节点指针指向下一节点
            back = tmp;
        }
        // 推出循环的时候当前节点指向空
        // 前任节点指向原先链表的最后一个节点
        return front;
    }
};

总结:

  • 注意指针的交换逻辑即可,该题难度不大
  • 做题体验:哈哈哈哈 > 嘿嘿 > 哎哎 > 嘤嘤
  • 时间:10min
  • 三刷
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值