代码随想录算法训练营第三天|203.移除链表元素、707.设计链表、206.反转链表

本文介绍了链表的一些关键操作,如使用虚拟头节点来简化移除元素的过程,以及如何通过双指针法来反转链表。在设计链表时,虚拟头节点的重要性得以凸显,它使得头节点的处理与其他节点一致。同时,文章强调了在进行链表操作时注意步骤顺序和指针管理的重要性。
摘要由CSDN通过智能技术生成

203.移除链表元素

力扣203

重点在认识到虚头节点的方便性。移除元素时要从这个元素的前一个结点p入手,p->next = p->next->next,另外要创建一个temp指针,把这个temp删掉。

返回时注意返回虚拟头节点的next,而不是直接返回head,因为head可能也会被删,虚拟头节点存在的意义就是使得对头节点的删除操作可以变得和其他节点一样。

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* myhead = new ListNode(0);
        myhead->next = head;
        ListNode* p = myhead;
        while(p->next){
            if(p->next->val==val){
                ListNode* t = p->next;
                p->next = t->next;
                delete t;
            }else
            p = p->next;
        }
        return myhead->next;
    }
};

 707.设计链表

这道题是理解链表的重中之重。

1.定义链表节点结构体

2.初始化链表时要创建虚拟头节点。

3.之后的链表操作基本步骤都是定义cur指向虚拟头结点,然后遍历到正确的位置执行插入或删除。因此要非常注意while的条件,以及步骤之间的执行顺序。

class MyLinkedList {

public:
    struct pNode {
        int val;
        pNode* next;
        pNode(int val):val(val), next(nullptr){}
    };
    MyLinkedList() {
        pHead = new pNode(0);
        size = 0;
    }
    int get(int index) {
        if(index>(size-1)||index<0){
            return -1;
        }
        int i=index;
        pNode* cur = pHead->next;
        while(i--){
            cur = cur->next;
        }
        return cur->val;
    }
    
    void addAtHead(int val) {
        pNode* t = new pNode(val);
        t->next = pHead->next;
        pHead->next = t;
        size++;
    }
    
    void addAtTail(int val) {
        pNode* tail = new pNode(val);
        pNode* cur = pHead;
        while(cur->next){
            cur = cur->next;
        }
        cur->next = tail;
        size++;
    }
    
    void addAtIndex(int index, int val) {
        if(index<=size){
            pNode* t = new pNode(val);//待插入的节点
            pNode* cur = pHead;
            while(index--){
                cur = cur->next;
            }
            t->next = cur->next;
            cur->next = t;
            size++;
        }        
    }
    
    void deleteAtIndex(int index) {
        if(index>(size-1)||index<0){
            return;
        }
        pNode* cur = pHead;
        while(index--){
            cur = cur->next;
        }
        pNode* t = cur->next;
        cur->next = t->next;
        delete t;
        t=nullptr;
        size--;
        
    }
private:
    int size = 0;
    pNode* pHead;
};

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList* obj = new MyLinkedList();
 * int param_1 = obj->get(index);
 * obj->addAtHead(val);
 * obj->addAtTail(val);
 * obj->addAtIndex(index,val);
 * obj->deleteAtIndex(index);
 */

 206.反转链表

力扣206

这里采用双指针法。

由于最后一个结点的next是NULL,那么反转前的pre也应该赋初值为NULL,而cur指向head;

 

 

我们希望反转方向,让cur->next = pre,但又不能让整个链表断,就需要先用t存储cur->next,然后再让cur->next = pre.

接着让pre和cur都往后移。必须先移pre,不然链表就断了,pre = cur,cur = t,这俩指针都挪到了它后面那个指针的位置。

再看while循环条件,最后结束时,cur指向最后的null,pre指向上图4的位置,也就是新的头结点。也就是while(cur)     和      return  pre;

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* pre = NULL;
        ListNode* cur = head;
        while(cur){//循环结束时cur指向NULL,不需要再动
            ListNode* t = cur->next;
            cur->next = pre;
            pre = cur;
            cur = t;
        }
        return pre;
    }
};

感想:

感觉链表的操作其实都不难,但是很注重一些while填什么,从哪个位置开始,步骤的先后顺序又是什么,需不需要temp指针临时存储以防断连这样的细节。需要我从目的操作出发,遇到问题思考对应的解决方案,弄清楚执行顺序。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值