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

203.移除链表元素、707.设计链表、206.反转链表

第一次写链表,很多操作都不太熟,浪费了很多时间,不过看了carl哥的讲解后,对这些问题也都搞明白了,今天头晕脑花的,再接再励吧

203.移除链表元素

对于移除链表,有两种解法,对应于自己是否去加一个虚拟的头节点
如果不加头节点,就需要对第一个元素进行判断是否等于目标值target

不加虚拟头节点

代码随想录算法训练营第三天| 203.移除链表元素、707.设计链表、206.反转链表_第1张图片
例如,head的值也是1,target也是1
此时就需要让head等于head->next
并且删除内存
而此时的head还是1,还需要再次进行相同操作
因此我们用while循环进行判断

while(head&&head->val==val)
       {
           ListNode* p =head;
           head = head->next;
           delete p;
       }

而对于非head元素p,
如果p->val = target
我们仅需要让前一个元素的next指向该元素的下一个元素
并删除该内存即可代码随想录算法训练营第三天| 203.移除链表元素、707.设计链表、206.反转链表_第2张图片

代码1

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        // 删除头结点
       while(head&&head->val==val)
       {
           ListNode* p =head;
           head = head->next;
           delete p;
       }
       ListNode*p = head;
       while(p&&p->next)
       {
           if(p->next->val ==val)
           {
               ListNode* temp = p->next;
               p->next=temp->next;
               delete temp;
           }
           else 
           p = p->next;
                
       }
       return head;
    }
};

添加虚拟头节点

假如我们添加了虚拟头节点,对于任意节点,我们都可以对其进行形如上述非头节点的操作
无需再判断是否是头节点在这里插入图片描述

代码2

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = 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;
    }
};

707、设计链表

设计链表真是一个大工程,耗时两个多小时,对链表debug真的太难熬了,大家可以像我一样,一个函数一个函数写,每写完一个函数进行一次运行,如果不是解答错误 就要看代码,就说明代码有了bug,如果是解答错误,就继续往下写,写完下一个函数,看看运行的案例有没有增加,可以判断这个函数错了没,最后也要全局debug。
接下来就要介绍这个题目了

大框架

首先,我们要用带虚拟头节点的单链表进行此次大工程,因为有虚拟头节点的存在,函数也会简便很多

定义节点

很显然,我们要定义一个节点,要包含它的值和指针,为了简便,笔者也定义了它的初始化

struct linkednode{
    int val;
    linkednode* next;
    linkednode(int val):val(val),next(nullptr){} 
};

对象MyLinkedList

我们定义它的构造函数,定义一个虚拟节点,用来引出链表

publicMyLinkedList() {
        virhead = new linkednode(0);
        size = 0;
    }
    linkednode *virhead;
    int size;

获取函数int get(int index)

对于get函数,
如果index范围越界,我们使其返回-1
我们可以让其进入循环,while(index–),当index为零时,遍历到我们想要的位置
因此此时,定义一个指针temp,temp初始应当指向虚拟头节点virtual

    int get(int index) {
        if(index>(size-1)||index<0)
        return -1;
        linkednode* p = virhead->next;
        while(index)
        {
            p=p->next;
            index--;
        }
        return p->val;
    }

头增函数void addAtHead(int val)

对于addAtHead函数,比较简单,我们直接开辟一个新节点,其值等于val,
让该节点next指向虚拟头节点的next,让虚拟头节点指向该节点,即可

    void addAtHead(int val) {
        linkednode *p = new linkednode(val);
        p->next = virhead->next;
        virhead->next = p;
        size++;
    }

尾增函数void addAtTail(int val)

对于 addAtTail函数,我们也可以先遍历该函数,先使指针指向尾部,再使尾指针指向一个新开辟节点,即可

    void addAtTail(int val) {
        linkednode *p = new linkednode(val);
        linkednode *temp = virhead;
        while(temp->next != nullptr)
        {
            temp = temp->next;
        }
        temp->next = p;
        size++;
    }

指定位置插入void addAtIndex(int index, int val)

对于addAtIndex函数,我们先判断index是否越界,不越界,我们遍历到指定位置,将节点插入

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

指定位置删除void deleteAtIndex(int index)

对于函数deleteAtIndex,先判断是否越界,在遍历到指定位置,删除即可

    void deleteAtIndex(int index) {
        if(index>=size||index<0)
         return ;
        linkednode *temp = virhead;
        while(index--)
        {
                temp = temp->next;
        }
        linkednode *temp0 = temp->next;
        temp->next = temp->next->next;
        size--;
        delete(temp0);
    }

代码

值得注意的是,对于每一个操作,我们可能需要对链表大小进行操作,即增加或减小或不变,只有实时改变链表大小,我们才能在操作之前的判断中,得到合适的结果

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

    MyLinkedList() {
        virhead = new linkednode(0);
        size = 0;
    }
    
    int get(int index) {
        if(index>(size-1)||index<0)
        return -1;
        linkednode* p = virhead->next;
        while(index)
        {
            p=p->next;
            index--;
        }
        return p->val;
    }
    
    void addAtHead(int val) {
        linkednode *p = new linkednode(val);
        p->next = virhead->next;
        virhead->next = p;
        size++;
    }
    
    void addAtTail(int val) {
        linkednode *p = new linkednode(val);
        linkednode *temp = virhead;
        while(temp->next != nullptr)
        {
            temp = temp->next;
        }
        temp->next = p;
        size++;
    }
    
    void addAtIndex(int index, int val) {
        if(index>size)
        return ;
        if(index<0)index = 0;
        linkednode *p = new linkednode(val);
        linkednode *temp = virhead;
        while(index--)
        {
                temp = temp->next;
        }
        p->next = temp->next;
        temp->next = p;
        size++;
    }
    
    void deleteAtIndex(int index) {
        if(index>=size||index<0)
         return ;
        linkednode *temp = virhead;
        while(index--)
        {
                temp = temp->next;
        }
        linkednode *temp0 = temp->next;
        temp->next = temp->next->next;
        size--;
        delete(temp0);
    }
    int size = 0;
    linkednode* virhead;
};

206.反转链表

反转链表,顾名思义,让其指针反过来就行,因此,我们记录下反转的指针
代码随想录算法训练营第三天| 203.移除链表元素、707.设计链表、206.反转链表_第3张图片
我们定义两个指针pre和cur,分别记作,前一个指针和当前运转的指针,起始时,令cur指向header,pre则为header的前一项,即为空,引入临时变量,使其记录cur的下一项,如图所示反转即可。
代码随想录算法训练营第三天| 203.移除链表元素、707.设计链表、206.反转链表_第4张图片

代码

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *pre = nullptr;
        ListNode *cur = head;
        while(cur!=nullptr)
        {
            ListNode *temp = cur->next;
            cur->next = pre;
            pre = cur;
            head = pre;
            cur = temp;
        }
        return head;
    }
};

你可能感兴趣的:(C++,leetcode,链表,算法,数据结构)