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

目录

前言

链表理论基础

LeetCode203.移除链表元素

LeetCode707.设计链表

LeetCode206.反转链表

一、LeetCode203 移除链表元素

题目链接:移除链表元素

原链表删除结点代码:

 原链表删除代码思路:

虚拟头结点代码:

虚拟头结点的代码思路:

二、LeetCode707 设计链表

题目链接:设计链表

设计单链表代码:

设计双链表代码:

代码思路:

三、LeetCode206 反转链表

题目链接:反转链表

新结点头插法:

 新结点头插法代码思路:

原地反转法:

原地反转发代码思路:


前言

链表理论基础

LeetCode203.移除链表元素

文章链接

视频链接

LeetCode707.设计链表

文章链接

视频链接

LeetCode206.反转链表

文章链接

视频链接


一、LeetCode203 移除链表元素

题目链接:移除链表元素

原链表删除结点代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        
        //先删除开头等于val的所有结点
        while(head && head->val == val)
        {
            ListNode* delNode = head;
            head = head->next;
            delete delNode;
        }
        
        ListNode *pHead = head;
        while(pHead && pHead->next)
        {
            if(pHead->next->val == val)
            {
                ListNode *delNode = pHead->next;
                pHead->next = pHead->next->next;
                delete delNode;
            }
            else{
                pHead = pHead->next;
            }
        }
        return head;
    }
};

 原链表删除代码思路:

首先要考虑要删除结点的位置不同会导致相应的代码不同,假如我们要删除值为2的结点,要删除的结点是头结点的位置,我们只需要移动head到head->next,然后释放原head位置的结点即可,如下图

 如果是删除的结点不是头结点,需要重新设置pCur来遍历头指针后的指针,通过pCur检查下一个指针是否为空,如果不为空,则检查pCur->next的值,如果值符合要删除的结点值,则先让pDel等于pCur->next,然后让pCur->next指向pCur->next->next,最后再删除结点pDel

虚拟头结点代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        //先给链表设置一个新的无值头指针,方便while中循环不变量
        ListNode *pHead = new ListNode();
        pHead->next = head;
        ListNode *pCur = pHead;
        while(pCur->next)
        {
            if(pCur->next->val == val)
            {
                ListNode *pDel = pCur->next;
                pCur->next = pCur->next->next;
                delete pDel;
            }
            else
                pCur = pCur->next;
        }

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

虚拟头结点的代码思路:

在原头节点head前添加一个无值的头节点pHead之后,后续删除代码的流程就不用像原链表删除方法那样需要考虑不同的情况了。直接按照同一种方法对结点进行删除即可。

二、LeetCode707 设计链表

题目链接:设计链表

设计单链表代码:

class MyListNode {
public:
    int val;
    MyListNode* next;
    MyListNode() {
        this->val = 0;
        this->next = nullptr;
    }
    MyListNode(int val):val(val), next(nullptr){}
};

class MyLinkedList {
public:
    MyListNode* head;
    int size;

    MyLinkedList() {
        this->head = new MyListNode();
        this->size = -1;
    }

    int get(int index) {
        if(this->size < index)
            return -1;
        MyListNode* pCur = this->head;
        for(int i = 0; i < index; i++)
        {
            pCur = pCur->next;
        }
        return pCur->next->val;
    }

    void addAtHead(int val) {
        MyListNode *newNode = new MyListNode(val);
        newNode->next = this->head->next;
        this->head->next = newNode;
        this->size += 1;
    }

    void addAtTail(int val) {
        MyListNode *pCur = this->head;
        while(pCur->next != nullptr)
        {
            pCur = pCur->next;
        }
        pCur->next = new MyListNode(val);
        this->size += 1;
    }

    void addAtIndex(int index, int val) {
        if(index > this->size + 1)
            return ;
        MyListNode* pCur = this->head;
        for(int i = 0; i < index; i++)
        {
            pCur = pCur->next;
        }
        MyListNode *newNode = new MyListNode(val);
        newNode->next = pCur->next;
        pCur->next = newNode;
        this->size += 1;
    }

    void deleteAtIndex(int index) {
        if(index > this->size)
            return ;
        MyListNode* pCur = this->head;
        for(int i = 0; i < index; i++)
        {
            pCur = pCur->next;
        }
        MyListNode *delNode = pCur->next;
        pCur->next = pCur->next->next;
        delete delNode;
        this->size -= 1;
    }
};

/**
 * 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);
 */

设计双链表代码:

class MyListNode{
public:
    int val;
    MyListNode *prev;
    MyListNode *next;
    MyListNode():val(0), prev(this), next(this){}
    MyListNode(int val):val(val), prev(this), next(this){}
};

class MyLinkedList {
public:
    MyListNode *head;
    int size;
    MyLinkedList() {
        this->head = new MyListNode();
        this->size = -1;
    }
    
    int get(int index) {
        if(index > this->size)
            return -1;
        MyListNode *pCur = this->head;
        while(index--)
        {
            pCur = pCur->next;
        }
        return pCur->next->val;
    }
    
    void addAtHead(int val) {
        MyListNode *newNode = new MyListNode(val);
        newNode->prev = this->head;
        newNode->next = this->head->next;
        this->head->next = newNode;
        newNode->next->prev = newNode;
        this->size += 1;
    }
    
    void addAtTail(int val) {
        MyListNode *newNode = new MyListNode(val);
        newNode->next = this->head;
        newNode->prev = this->head->prev;
        this->head->prev = newNode;
        newNode->prev->next = newNode;
        this->size += 1;
    }
    
    void addAtIndex(int index, int val) {
        if(index > this->size + 1)
        {
            return ;
        }
        MyListNode *pCur = this->head;
        while(index--)
        {
            pCur = pCur->next;
        }
        MyListNode *newNode = new MyListNode(val);
        newNode->prev = pCur;
        newNode->next = pCur->next;
        pCur->next = newNode;
        newNode->next->prev = newNode;

        this->size += 1;
    }
    
    void deleteAtIndex(int index) {
        if(index > this->size)
            return ;
        MyListNode *pCur = this->head;
        while(index--)
        {
            pCur = pCur->next;
        }
        MyListNode *delNode = pCur->next;
        pCur->next = pCur->next->next;
        delNode->next->prev = pCur;
        delete delNode;
        this->size -= 1;
    }
};

/**
 * 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);
 */

代码思路:

无论是单双链表都需要设置一个新的结点类MyListNode,然后根据单双链表的结构不同,添加和删除有所不同,单链表的增删比较固定,只能添加或者删除某个结点后面的结点,所以确定添加或者删除位置的时候,我们要找到该位置的前一个结点,然后再进行添加或者删除。双链表既可以找到当前位置结点之后进行增删,也可以找到前后结点进行增删。

三、LeetCode206 反转链表

题目链接:反转链表

新结点头插法:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *newHead = new ListNode();
        ListNode *pCur = head;
        ListNode *temp = nullptr;
        while(pCur)
        {
            temp = pCur->next;
            pCur->next = newHead->next;
            newHead->next = pCur;
            pCur = temp;
        }
        head = newHead->next;
        delete newHead;
        return head;
    }
};

 新结点头插法代码思路:

创建一个新的空值头结点,将head从头到尾的结点采用头插法插入到新的头结点上,就可以直接得到一个反转后的链表。

原地反转法:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *pCur = head;
        ListNode *pPre = nullptr;
        ListNode *temp = nullptr;
        while(pCur)
        {
            temp = pCur->next;
            pCur->next = pPre;
            pPre = pCur;
            pCur = temp;
        }
        return pPre;
    }
};

原地反转发代码思路:

原地反转需要设置三个指针,如下图,pCur指向的结点是当前要进行反转的结点,pPre指向的结点是前一个反转的结点,temp是用来记录下一次pCur的位置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值