代码随想录算法训练营29期Day3|LeetCode 203,707,206

 文档讲解:代码随想录

203.移除链表元素

题目链接:https://leetcode.cn/problems/remove-linked-list-elements/

思路:

        题目的本质就是让我们学会如何删除链表中的节点,是否需要删除看节点的值是否与目标值val相同。

        删除操作其实也很简单,假设链表中我们要删除q节点,经过遍历我们可以得到q前后的两个节点p和r。满足p->next=q,q->next=r。那我们如何将q删除呢,直接让p指向r即可,即直接:p->next=r,一般来说,我们直接使用p->next=q->next即可。

核心代码:

/**
 * 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* dhead=new ListNode(0);
        dhead->next=head;
        ListNode* tmp=dhead;
        while(tmp->next!=NULL){
            if(tmp->next->val==val){
                ListNode* p=tmp->next;
                tmp->next=p->next;
                delete p;
            }
            else tmp=tmp->next;
        }
        head=dhead->next;
        delete dhead;
        return head;
    }
};

707.设计链表

题目链接:https://leetcode.cn/problems/design-linked-list/

思路:

       本题目要求我们实现一个链表类型。

        首先我们需要定义链表节点类型,才能在此基础上实现整个链表。同时我定义了链表的头结点head。除了上述必须的变量,我额外定义了链表节点数目cnt,方便判断下标是否在范围内。

        本题目要求实现的函数有六个,但实际上经过归类分析,是让我们做三件事:链表节点的查看、插入和删除。

        首先,链表节点值的查看依次序遍历整个链表即可,到达指定下标后输出节点中的值。

        其次,在链表中指定节点前后插入节点,实际上是一类操作。对于在下标为index的节点前插入,其实就是在下标为(index-1)的节点后插入。因此插入操作我们可以分为两步走,即寻找到目标节点,然后插入。寻找目标节点遍历链表即可,不再赘述。下面叙述插入操作:

        假设我们已经寻找到了目标节点p,下面在p之后插入节点r。我们易知,p原本指向的节点为q=p->next,接下来我们只需要让p指向r,r再指向q,就完成了插入操作。即:p->next=r,r->next=q。经调整顺序我们可以省略掉q的定义,即:r->next=q->next,q->next=r。

        最后,链表节点的删除,这一点与本文章第一道题目LeetCode203相同,也不再赘述。

核心代码:

class MyLinkedList {
private:
    struct ListNode {
        int val;
        ListNode *next;
        ListNode(){
            val=0;
            next=NULL;
        }
    };
    ListNode* head;
    int cnt;
public:
    MyLinkedList() {
        head=new ListNode();
        cnt=0;
    }
    
    int get(int index) {
        if(index>=cnt) return -1;
        else{
            ListNode* cur=head;
            index++;
            while(index--) cur=cur->next;
            return cur->val;
        }
    }
    
    void addAtHead(int val) {
        ListNode* p=new ListNode();
        p->val=val;
        p->next=head->next;
        head->next=p;
        cnt++;
    }
    
    void addAtTail(int val) {
        ListNode* cur=head;
        while(cur->next!=NULL) cur=cur->next;
        ListNode* p=new ListNode();
        p->val=val;
        p->next=NULL;
        cur->next=p;
        cnt++;
    }
    
    void addAtIndex(int index, int val) {
        if(index==cnt) addAtTail(val);
        else if(indexnext;
            ListNode* p=new ListNode();
            p->val=val;
            p->next=cur->next;
            cur->next=p;
            cnt++;
        }
    }
    
    void deleteAtIndex(int index) {
        if(cnt>index){
            ListNode* cur=head;
            while(index--) cur=cur->next;
            ListNode* p=cur->next;
            cur->next=p->next;
            cnt--;
        }
    }
};

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

题目链接:https://leetcode.cn/problems/reverse-linked-list/

思路:

        本题目要求将一个单链表进行反转,给出了链表节点的定义和头节点。

        一种简单的做法是开个新链表,对旧链表利用递归或迭代进行遍历,这个做法简单易懂,但是会占用比较多的空间。

        本文用的方法是在原来链表的基础上直接进行反转操作,这样不会占用新空间,时间复杂度也低,因为只需要将原链表遍历一遍即可,下面分析如何实现。

        首先,我们易知单链表为空或者只有一个结点时,我们不需要反转,直接返回即可。

        接下来我们考虑现在有两个节点p和q,p和q从head开始移动,满足在原链表上q为p的后继,即p->next=q。首先我们考虑将q->next=p,这样即完成了p和q之间的反转,由于我们在链表上按照顺序移动,因此q之前的节点都完成了反转。但是如果直接写q->next=p,q原本的后继会丢失,我们无法继续移动,因此考虑开第三个节点r存放原本的p->next,然后移动的时候将p=q,q=r即可。

        将上面一段用代码表示就是r=q->next,q->next=p,p=q,q=r。p和q从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) {
        if(head==NULL||head->next==NULL) return head;
        ListNode* p=head;
        ListNode* q=head->next;
        head->next=NULL;
        while(q!=NULL){
            ListNode* cur=q->next;
            q->next=p;
            p=q;
            q=cur;
        }
        return p;
    }
};

今日总结

        今日学习时长4h,做题手感变好,思路更加清晰,感觉状态慢慢回暖。

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