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

203.移除链表元素

题目链接:https://leetcode.cn/problems/remove-linked-list-elements/
文章讲解:https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html
视频讲解:https://www.bilibili.com/video/BV18B4y1s7R9/
状态:做了出来,但未去删废弃节点

思路

自己看到题目的第一想法:
正常的链表删除节点操作
看完代码随想录之后的想法:
正常删除节点操作后,需要删除废弃的节点;同时也可以使用虚拟的头节点来避免头节点和后面的节点操作不一致的问题\

实现代码中遇到的苦难

自己在实现的时候,老是忘记判断头节点是否为空这一情况
设置新节点未掌握,ListNode* dummy_head = new ListNode(0);
同时,自己在实现while循环中的if语句时,后来省略else发现行不通,因为此时满足if是另一种条件的不必再else了,因此想省去要考虑能否成功

代码实现

①正常删除

/**
 * 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* temp = head;
            head = head -> next;
            delete temp;
        }
        ListNode* current = head;
        while(current != NULL && current -> next != NULL){
            if(current -> next -> val == val){
                ListNode* temp = current -> next;
                current -> next = current -> next -> next;
                delete temp;
            }else{
                current = current -> next;
            }
        }
        return 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* removeElements(ListNode* head, int val) {
        ListNode* dummy_head = new ListNode(0);
        dummy_head -> next = head;
        ListNode* current = dummy_head;
        while(current != NULL && current -> next != NULL){
            ListNode* temp = current -> next;
            if(current -> next -> val == val){
                current -> next = current -> next -> next;
                delete temp;
            }else{current = current -> next;}
        }
        head = dummy_head -> next;
        delete dummy_head;
        return head;
    }
};

707.设计链表

题目链接:https://leetcode.cn/problems/design-linked-list/
文章讲解:https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
视频讲解:https://www.bilibili.com/video/BV1FU4y1X7WD
状态:思想会,但是如何实现却不会

思路

利用虚拟头节点,一步步去按照链接的增删改查去实现

206.翻转链表

题目链接:https://leetcode.cn/problems/reverse-linked-list/
文章讲解:https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html
视频讲解:https://www.bilibili.com/video/BV1nB4y1i7eL
状态:未写

今天白天在忙着完成老师布置的任务,晚上吃过晚饭完了一个小时,从9点开始,就完成了一道完整的题,为了防止赶不上,这个卡我今天先打了,明天再回来补充设计链表的代码,寻找自己写不出代码的困难在哪里,以及完整的做一遍反转链表

================================================================

707.设计链表

代码实现过程中遇到的困难

我自己实现的实现忽略了index是从0开始的这一条件,另外没注意添加时题目给的限制条件

代码随想录中用的while(index–)代替while(count!=index)更好用,此时要注意cur是要从虚拟头节点开始,还是从头节点开始

代码实现

class MyLinkedList {
public:
    MyLinkedList() {
        dummy_head = new ListNode(0);
        size = 0;
    }
    
    int get(int index) {
        ListNode* current = dummy_head -> next;
        if(index < 0 || index > (size - 1)){
            return -1;
        }
        while(index --){
            current = current -> next;
        }
        return current -> val;
    }
    
    void addAtHead(int val) {
        ListNode* current = new ListNode(val);
        current -> next = dummy_head -> next;
        dummy_head -> next = current;
        size ++;
    }
    
    void addAtTail(int val) {
        ListNode* current = dummy_head;
        while(current -> next != NULL){
            current = current -> next;
        }
        ListNode* tail = new ListNode(val);
        current -> next = tail;
        size ++;
    }
    
    void addAtIndex(int index, int val) {
        if(index < 0){
            index = 0;
        }
        if(index > size){
            return ;
        }
        ListNode* current = dummy_head;
        while(index --){
            current = current -> next;
        }
        ListNode* tmp = new ListNode(val);
        tmp -> next = current -> next;
        current -> next = tmp;
        size ++;
    }
    
    void deleteAtIndex(int index) {
        if(index < 0 || index >= size){
            return ;
        }
        ListNode* current = dummy_head;
        while(index --){
            current = current -> next;
        }
        ListNode* tmp = current -> next;
        current -> next = tmp -> next;
        delete tmp;
        tmp = nullptr;
        size --;
    }
    private:
        ListNode* dummy_head;
        int size;
};

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

思路

首先说非递归,非递归就是设置一个pre和一个当前节点,一步一步的走,并将其反转
第一种递归,就是用递归实现上面非递归的思想,但是其中的重点在于递归的出口怎么找,完全不变的把非递归变为递归,是要把头节点为空和最后一个节点单独拿出来,并把最后一个节点作为出口,但是可以简化,当cur为空时返回pre,这样,就更简单了
第二种递归,从第二个开始递归反转,我认为做这样的递归不要去递归中的细节

代码实现

①非递归

/**
 * 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* pre = NULL;
        ListNode* cur = head;
        if(head == NULL){
            return head;
        }
        while(cur -> next != NULL){
            ListNode* tmp = cur -> next;
            cur -> next = pre;
            pre = cur;
            cur = tmp;
        }
        cur -> next = pre;
        return cur;
    }
};

②第一种递归

/**
 * 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-> next == NULL){
            cur -> next = pre;
            return cur;
        }
        ListNode* tmp = cur -> next;
        cur -> next = pre;
        return reverse(cur, tmp);
    }
    ListNode* reverseList(ListNode* head) {
        if(head == NULL){
            return head;
        }
        return reverse(NULL, 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) return NULL;
        if(head -> next == NULL) return head;
        ListNode* last;
        last = reverseList(head -> next);
        head -> next -> next = head;
        head -> next = NULL;
        return last;
    }
};

收获

在对链表进行操作时,我们可以引入虚拟头节点,增加效率
可以用while(index–)来找到对应索引的节点
递归时,巧妙的合二为一,以及直接从第二个开始

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值