代码随想录算法训练营Day 3|LeetCode203 移除链表元素、Leetcode707 设计链表、Leetcode206 反转链表

LeetCode203 移除链表元素

题目链接:移除链表元素

思路

因为该链表没有头结点,和考研时学的还有点出入,不过只是在处理首元结点上有点差异,单独处理即可,思路为:①若head->val==val,则直接将head指针后移并释放掉原首元结点即可;②若工作指针p->next->val==val,则将p->next=p->next->next,然后将原p->next释放。注:之前DS上的代码基本都是伪代码,对于指针置空或者边界条件都没有很严格,导致自己在这上面也是翻了些错——俩while循环里面的指针一开始都忘记加不为空的条件导致执行错误。

扩展思路:可以像之前学的,给该链表加上一个头结点Lnodehead,这样该链表后续所有结点删除操作都一致,无需再单独讨论首元结点,最后返回Lnodehead->next即可。

代码

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        if (head == nullptr)
            return nullptr;
        while (head != nullptr && head->val == val) { //首元结点单独处理
            ListNode* temp = head;
            head = head->next;
            delete temp;
        }
        ListNode* p = head;
        while (p != nullptr && p->next != nullptr) {
            if (p->next->val == val) {
                ListNode* temp = p->next;
                p->next = p->next->next;
                delete temp;
            } else {
                p = p->next;
            }
        }
        return head;
    }
};

附随想录中带虚拟头结点代码

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
        dummyHead->next = head; // 将虚拟头结点指向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;
        delete dummyHead;
        return head;
    }
};

复杂度

时间复杂度 O(n)

空间复杂度O(1)

Leetcode707 设计链表

题目链接:设计链表

思路

本题较上题就采用了使用头结点的做法,并增加size字段以便于判断范围:①get,对于不在范围内index返回-1,在范围内便遍历到该处然后返回对应的值;②addAtHead,头插法,注意顺序防断链即可;③addAtTail,尾插法,一开始想减少时间耗费使用尾指针,但是头插按标号插入的情况尾指针不方便修改,于是改用直接遍历一遍链表,在末尾插入;④addAtIndex,按标号插入,遍历链表至index位置插入即可。实现头插和尾插时也可以直接调用该函数 ⑤deleteAtIndex,按标号删除,也是先查找到相应位置然后执行删除操作。

代码

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

    MyLinkedList() {
        Lnodehead = new ListNode(0);
        size = 0;
    }

    int get(int index) {
        if (index >= size || index < 0)
            return -1;

        ListNode* p = Lnodehead->next;
        while (index--) {
            p = p->next;
        }
        return p->val;
    }

    void addAtHead(int val) { //头插
        ListNode* temp = new ListNode(val);
        temp->next = Lnodehead->next; //注意顺序防止断链
        Lnodehead->next = temp;
        size++;
    }

    void addAtTail(int val) { //尾插
        ListNode* temp = new ListNode(val);
        ListNode* p = Lnodehead;
        while (p->next != nullptr) {
            p = p->next;
        }
        p->next = temp;
        size++;
    }

    void addAtIndex(int index, int val) {
        if (index <= size && index >= 0) {
            ListNode* temp = new ListNode(val);
            ListNode* p = Lnodehead;
            while (index--) {
                p = p->next;
            }
            temp->next = p->next;
            p->next = temp;
            size++;
        }
    }

    void deleteAtIndex(int index) {
        if (index < size && index >= 0) {
            ListNode* p = Lnodehead;
            while (index--) {
                p = p->next;
            }
            ListNode* temp = p->next;
            p->next = p->next->next;
            delete temp;
            size--;
        }
    }

private:
    int size;
    ListNode* Lnodehead;
};

复杂度

时间复杂度 get、addAtIndex、deleteAtIndex: O(index) 

                   addAtHead:O(1) 

                   addAtTail:O(len),其中len为链表长度

空间复杂度O(1)

Leetcode206 反转链表

题目链接:反转链表

思路

链表逆置,通过双指针可完成:设置工作指针p初始为head,p前置指针pre初始为Null。当p不为Null时循环,利用temp暂存p-next,防止断链,并将p->next=pre完成一个结点的逆置,最后更新pre和p。循环结束后pre即指向逆置后链表的头结点,返回。

代码

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* p=head;  //工作指针
        ListNode* pre=nullptr; //p前置
        while(p!=nullptr){
            ListNode* temp=p->next; //防断链
            p->next=pre;            //逆置
            //更新指针
            pre=p;
            p=temp;
        }
        return pre;
    }
};

复杂度

时间复杂度 O(n)

空间复杂度O(1)

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Rust 是一种现代的编程语言,特别适合处理内存安全和线程安全的代码。在 LeetCode 中,链表是经常出现的题目练习类型,Rust 语言也是一种非常适合处理链表的语言。接下来,本文将从 Rust 语言的特点、链表的定义和操作,以及 Rust 在 LeetCode链表题目的练习等几个方面进行介绍和讲解。 Rust 语言的特点: Rust 是一种现代化的高性能、系统级、功能强大的编程语言,旨在提高软件的可靠性和安全性。Rust 语言具有如下几个特点: 1. 内存安全性:Rust 语言支持内存安全性和原语级的并发,可以有效地预防内存泄漏,空悬指针以及数据竞争等问题,保证程序的稳定性和可靠性。 2. 高性能:Rust 语言采用了“零成本抽象化”的设计思想,具有 C/C++ 等传统高性能语言的速度和效率。 3. 静态类型检查:Rust 语言支持静态类型检查,可以在编译时检查类型错误,避免一些运行时错误。 链表的定义和操作: 链表是一种数据结构,由一个个节点组成,每个节点保存着数据,并指向下一个节点。链表的定义和操作如下: 1. 定义:链表是由节点组成的数据结构,每个节点包含一个数据元素和一个指向下一个节点的指针。 2. 操作:链表的常用操作包括插入、删除、查找等,其中,插入操作主要包括在链表首尾插入节点和在指定位置插入节点等,删除操作主要包括删除链表首尾节点和删除指定位置节点等,查找操作主要包括根据数据元素查找节点和根据指针查找节点等。 Rust 在 LeetCode链表题目的练习: 在 LeetCode 中,链表是常见的题目类型,而 Rust 语言也是一个非常适合练习链表题目的语言。在 Rust 中,我们可以定义结构体表示链表的节点,使用指针表示节点的指向关系,然后实现各种操作函数来处理链表操作。 例如,针对 LeetCode 中的链表题目,我们可以用 Rust 语言来编写解法,例如,反转链表,合并两个有序链表,删除链表中的重复元素等等,这样可以更好地熟悉 Rust 语言的使用和链表的操作,提高算法和编程能力。 总之,在 Rust 中处理链表是非常方便和高效的,而 LeetCode 中的练习也是一个非常好的机会,让我们更好地掌握 Rust 语言和链表数据结构的知识。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值