【算法训练 day3 移除链表元素、设计链表、反转链表】

本文概述了LeetCode中的三个链表相关问题:移除链表中等于给定值的节点、设计支持多种操作的链表类以及反转链表。作者分享了解决思路、代码实现和个人问题总结,强调了链表操作中的关键技巧和注意事项。
摘要由CSDN通过智能技术生成


一、移除链表元素-LeetCode 203

Leecode链接: leetcode 203
文章链接: 代码随想录
视频链接: B站

题意:删除链表中等于给定值 val 的所有节点。

示例:

输入:head = [1,2,6,3,4,5,6], val = 6 
输出:[1,2,3,4,5]

思路

基础数据结构题目,删除节点时,遍历指针需要指向前一个指针来保存所删除结点地址,由于头节点可能符合条件,所以需要设置一个虚拟头节点,便于数据删除。

实现代码

//cpp
    ListNode* removeElements(ListNode* head, int val) {
        if(head == nullptr){//空链表直接返回本身
            return head;
        }
		//不为空链表则构造虚拟头节点
        ListNode *vhead = new ListNode(-1);//考虑头节点数据无意义,取-1
        ListNode *p = nullptr;//指针
        vhead ->next = head;//构建空的头节点
        p = vhead;

        while(p->next){
            if(p->next->val == val){
                ListNode *a = p->next;//保存节点
                p->next = a->next;
                delete a;
                a = nullptr;
            }
            else{
                p = p->next;
            }
        }

        head = vhead->next;
        delete vhead;
        return head;
    }

个人问题

熟练度不够,没有立马写出代码。

总结

整体比较简单,需要注意链表循环的退出条件以及删除节点后需要delete以及置空,避免出现未定义行为;删除节点后由于头节点可能被删除,所以返回时需要返回虚拟头节点的下一个节点,即vhead->next。


二、设计链表-LeetCode 707

Leecode链接: LeetCode 707
文章链接: 代码随想录
视频链接: B站

在链表类中实现这些功能:
1.get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
2.addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
3.addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
4.addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
5.deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

思路

相当于写一个不带模板的只支持存储int类型的list。

实现代码

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

    MyLinkedList() {
        dum = new LinkedNode(0);
        size = 0;
    }
    
    //搜索节点
    int get(int index) {
        if((index>(size-1))||(index < 0)){
            return -1;
        }

        LinkedNode *p = dum->next;
        while(index--){
            p = p->next;
        }
        return p->val;
    }
    
    //头插
    void addAtHead(int val) {
        LinkedNode *p = new LinkedNode(val);
        p->next = dum->next;
        dum->next = p;
        size++;
    }
    
    //尾插
    void addAtTail(int val) {
        LinkedNode *m = new LinkedNode(val);
        LinkedNode *p = dum;
        while(p->next != nullptr){
            p = p->next;
        }

        p->next = m;
        size++;
    }
    
    void addAtIndex(int index, int val) {
        LinkedNode *p = dum;
        if(index>size){
            return ;
        }

        if(index<0){
            index = 0;
        }

        while(index--){
            p = p->next;
        }

        LinkedNode *m = new LinkedNode(val);
        m->next = p->next;
        p->next = m;
        size++;
    }
    
    //删除节点
    void deleteAtIndex(int index) {
        LinkedNode *p = dum;
        if(index>=size||size == 0){
            return ;
        }

        while(index--){
            p = p->next;
        }

        LinkedNode *m = p->next;
        p->next = m->next;
        delete m;
        m = nullptr;
        size--;
    }

    void printLinkedList(){
        LinkedNode *cur = dum->next;
        while(cur){
            cout<<cur->val;
            cur = cur->next;
        }
        cout<<endl;
    }

private:
    int size;
    LinkedNode *dum;
};

个人问题

熟练度不够

总结

链表的操作实现没有难点只有熟练度问题。


三.反转链表-LeeCode 206

Leecode链接: LeetCode 206
文章链接: 代码随想录
视频链接: B站

题意:反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL 
输出: 5->4->3->2->1->NULL

思路

使用双指针,我个人还是理解为三指针,因为双指针无法保存需要插入节点的地址,所以需要有一个中间变量来保存快指针的next,保证当快指针的next指向慢指针时,原有的next值不会丢失。慢指针表示指向已经反转完成的链表的头结点,快指针表示指向待插入的节点,将快指针的next赋值给慢指针,也就实现了由1->2转化为2->1,然后将快指针的地址赋值给慢指针,将中间变量的地址赋值给快指针,为下一个循环做准备,直到快指针为nullprt时退出循环,此时慢指针为新的链表头节点。

实现代码

//cpp
	ListNode* reverseList(ListNode* head) {
        if(head == nullptr) return head;

        ListNode *fast = head;
        ListNode *slow = nullptr;

        while(fast){
            ListNode* cur = fast->next;
            fast->next = slow;
            slow = fast;
            fast = cur;
        }

        return slow;
    }

个人问题

while循环的退出条件写的不够熟练,容易出现访问非法空间导致未定义行为。

总结

总体简单,在单链表中,对链表的操作如果涉及删除添加,都需要有一个指针去指向需要操作节点的前一个节点,这样才能保证链表的连贯性。时间复杂度O(n),空间复杂度O(1)。

  • 21
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值