您现在的位置是:首页 >学无止境 >代码随想录算法训练营第三天 | 203.移除链表元素、 707.设计链表、206.反转链表网站首页学无止境

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

玛玛哈哈34 2024-10-09 12:01:04
简介代码随想录算法训练营第三天 | 203.移除链表元素、 707.设计链表、206.反转链表


一、203.移除链表元素

1.使用原链表进行移除节点操作

代码如下:

/**
 * 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 (head != NULL && head->val == val){
            ListNode* tmp = head;//(1)
            head = head->next;
            delete tmp;//(2)
            //(1)、(2)两句的作用是C++释放空间
        }

        ListNode* cur = head;
        while (cur != NULL && cur->next != NULL){//cur不能为空,因为接下来要操作cur->next,cur为空的话会出现空指针报错
                                                //cur->next也不能为空,因为要去cur->next的值和val进行对比,如果cur->next为空,有属于操作空指针了
           if (cur->next->val == val){
            ListNode* tmp = cur->next;//因为比较的是cur->next的值,因此tmp要设置为cur->next。tmp可以理解为待删除的值
            cur->next = cur->next->next;
            delete tmp;
           }

           else{
               cur = cur->next;
           }
           
        }
        return head;//因为定义了一个临时指针cur,是使用cur来进行遍历的,head还是指向一开始操作的链表
    }
};

注意:
1、如果直接用头节点head遍历链表,那么这个头节点指向的值是不断变化的,最后就没有办法返回原先链表的头节点了。所以要定义一个临时的指针cur来遍历链表
2、要删的是cur的next,要删一个元素的话,一定要知道上一个元素的指针是什么,所以上一个只能是cur。删cur的next的话,才能让cur的指针指向下一个节点的下一个节点
3、使用虚拟头节点时,为什么返回dummyHead->next而不是head,因为head可能已经被删了,dummyHead的下一个(dummyHead->next)才是新链表的头节点

2.设置一个虚拟头节点进行移除节点操作

代码如下:

/**
 * 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) {
        ListNode* dummyHead = new ListNode(0); //new操作符的使用要再看看
        dummyHead->next = head;
        ListNode* cur = dummyHead;
        while(cur->next != NULL){//注意!!要操作的对象是cur->next,所以要判断cur->next这个指针是否为空,不能操作空指针
            if (cur->next->val == val){
                ListNode* tmp = cur->next;//注意!!要删除的是cur->next,不是cur!
                cur->next = cur->next->next;
                delete tmp;
            }
            else{
                cur = cur->next;
            }
        }

        head = dummyHead->next;
        delete dummyHead;
        return head;//新链表的头节点为dummy->next,不能直接返回dummy->next,因为C++需要手动清理内存
    }
};

二、707.移除链表元素

class MyLinkedList {
public:

    //定义链表节点结构体
    struct LinkedNode {
        int val;
        LinkedNode* Next;
        LinkedNode(int val):val(val), Next(nullptr){}//链表节点的构造函数
        //LinkedNode是链表节点的类名
        //int val是节点的值,是一个整数
        //构造函数初始化了该节点的值val作为传入的参数val,初始化了指针next为空指针
    };


    MyLinkedList() {
        _dummyHead = new LinkedNode(0);
        _size = 0;
    }
    
    int get(int index) {
        if (index > (_size - 1) || index < 0) {
            return -1;
        }
        LinkedNode* cur = _dummyHead->Next;
        while (index--){
            cur = cur->Next;
        }
        return cur->val;
    }
    
    void addAtHead(int val) {
        LinkedNode* newNode = new LinkedNode(val);//创建一个新结点 //new操作符的语法还不太懂
        newNode->Next = _dummyHead->Next;//不写=head的原因:能够获取head的地址,在_dummyHead->next中
        _dummyHead->Next = newNode;
        //这里有一个先后顺序,要先把新节点和头节点链接,再把虚拟头节点和新节点链接;否则,先将虚拟头节点和新节点链接后,无法获取头节点的地址(头节点的地址存在虚拟头节点的next指针中)
        _size++;
    }
    
    void addAtTail(int val) {
        LinkedNode* newNode = new LinkedNode(val);
        LinkedNode* cur = _dummyHead;
        //当前遍历指针一定要指向尾部节点,要找尾部节点
        while (cur->Next != nullptr){//cur->next=NULL时即尾部节点,不为空就一直遍历
            cur = cur->Next;
        }
        cur->Next = newNode;//newnode在定义的时候默认next=NIULL
        _size++;

    }
    
    void addAtIndex(int index, int val) {
        if (index > _size) {//如果index大于链表长度,返回空
            return ;
        }
        LinkedNode* newNode = new LinkedNode(val);
        LinkedNode* cur = _dummyHead;
        while (index--) {
            cur = cur->Next;
        }
        newNode->Next = cur->Next;//cur已经遍历到需要插入的位置
        cur->Next = newNode;
        _size++;

    }
    
    void deleteAtIndex(int index) {//要删第n个节点,一定需要知道前一个节点的next,因为要让它指向n后的节点
        if (index >= _size || index < 0){//为什么上面一个>,这个是>=?
            return ;
        }
        LinkedNode* cur = _dummyHead;
        while (index--) {
            cur = cur->Next;
        }
        LinkedNode* tmp = cur->Next;
        cur->Next = cur->Next->Next;
        delete tmp;
        _size--;
    }

    private:
        int _size;
        LinkedNode* _dummyHead;
};

/**
 * 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.反转链表

/**
 * 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* reverse(ListNode* pre, ListNode* cur) {
       if (cur == NULL) return pre;
       struct ListNode* tmp = cur->next;
       cur->next = pre;
       return reverse(cur, tmp);
   }
   
    ListNode* reverseList(ListNode* head) {
       return reverse(NULL, head);
    }
     
    
};
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。