记录算法Day3

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

Leetcode 203 移除链表元素

题目链接 203.移除链表元素
文章链接 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

思路

这道题本质就是链表的删除操作,链表删除时要考虑满足条件的点是头结点的情况。我是对原始链表直接操作的,看了卡哥的讲解之后,可以定义一个虚拟头节点,其实就是把原来的头节点当作普通节点,这样就不用多判断一次,代码看起来也比较舒服一些。最重要的还是链表删除时将前一个节点指向当前节点(满足条件的点,用temp临时存储)的下一个节点,并释放temp

代码

  • 对原始链表操作
class Solution {

public:

    ListNode* removeElements(ListNode* head, int val) {

        ListNode* cur = head;

        ListNode* pre = nullptr;

        while(cur){

            if(cur->val==val){

                ListNode* temp = cur;

                cur = cur->next;

                if(!pre){//当前满足条件的点是头节点的情况

                    head = cur;

                    delete temp;

                }else{

                    pre->next = cur;

                    delete temp;

                }

            }else{

                pre = cur;

                cur = cur->next;

            }

        }

        return head;

    }

};
  • 虚拟头节点
class Solution {

public:

    ListNode* removeElements(ListNode* head, int val) {

        ListNode* dummyHead = new ListNode(-1);//定义虚拟头节点,省去判断满足条件的点是否为头节点的步骤

        dummyHead->next = head;

        ListNode* cur = dummyHead->next;//定义当前节点

        ListNode* pre = dummyHead;//定义当前节点的上一个节点

        while(cur){

            if(cur->val==val){

                ListNode* temp = cur;//当前节点满足条件,用临时节点存储并释放

                cur = cur->next;

                pre->next = cur;//让上一个节点指向当前节点的下一个节点

                delete temp;//释放临时节点,也就是满足条件的当前节点

                continue;

            }else{

                pre = cur;

                cur = cur->next;

            }

        }

        head = dummyHead->next;

        delete dummyHead;//最好把虚拟头节点释放,节省不必要的内存空间

        return head;

    }

};

Leecode 707 设计链表

题目链接 707. 设计链表
文章链接 https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html
视频链接 https://www.bilibili.com/video/BV1FU4y1X7WD
卡哥讲解虚拟头节点(虽然会占用一些空间,但写起来会方便很多) https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html

思路

这道题考的可太全面了,单把每个函数拿出来其实就是基本的链表的操作,但是放在一起时,每个函数都要先判断head是否为空,不为空的话就是单纯的链表操作了。我也是写了很久,一些操作比如说计算长度,定义虚拟头节点重复好多次,费时间和空间,贡献了leetcode用时最长的解法(放在下面,记录一下自己最开始的想法)。

  • 优化
class MyLinkedList {

public:

    struct ListNode{//构造一个链表

        int val;

        ListNode* next;

        ListNode(int x):val(x),next(nullptr){}

    };

    MyLinkedList() {

        _dummyHead = new ListNode(0);//初始化虚拟头节点

        _size = 0;

    }

    int get(int index) {

        if((index>_size-1)||(index<0)){//index不满足条件退出

            return -1;

        }

        ListNode* cur = _dummyHead->next;

        while(index--){

            cur = cur->next;

        }

        return cur->val;

    }

    void addAtHead(int val) {

        ListNode* point = new ListNode(val);

        ListNode* cur = _dummyHead;

        point->next = _dummyHead->next;//如果head为空,也就是point->next=nullptr,相当于head节点,就不用多判断一次head的条件
        
        _dummyHead->next = point;
        
        _size++;

    }

    void addAtTail(int val) {

        ListNode* point = new ListNode(val);

        ListNode* cur = _dummyHead;

        while(cur->next){//到链表的最后一个位置截至

            cur = cur->next;

        }

        cur->next = point;

        _size++;

    }

    void addAtIndex(int index, int val) {

        if((index>_size)||(index<0)){

            return;

        }else if(index==_size){

            addAtTail(val);

            return;

        }else{

            ListNode* cur=_dummyHead->next;

            ListNode* pre=_dummyHead;//当前节点的前一个结点

            while(index--){

                pre = cur;

                cur = cur->next;

            }

            ListNode* point = new ListNode(val);

            point->next = cur;

            pre->next = point;

            _size++;

        }

        return;

    }

    void deleteAtIndex(int index) {

        if((index>_size-1)||(index<0)) return;

        ListNode* pre = _dummyHead;

        ListNode* cur = _dummyHead->next;

        while(index--){

            pre = cur;

            cur = cur->next;

        }

        pre->next = cur->next;

        delete cur;

        _size--;

    }

private:

    ListNode* _dummyHead;//虚拟头节点,私有成员变量最好加上'_'

    int _size;//链表大小

};
  • 原始代码

class MyLinkedList {

public:

    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){}

    };

    ListNode* head = nullptr;//初始化head节点为空

    MyLinkedList() {

    }

    int get(int index) {

        int len = 0;

        int p = 0;

        if(!head){

            return -1;

        }//判断head节点是否为空

        ListNode* cur = head;

        for(cur=head;cur;cur=cur->next) len++;

        //cout<<len<<endl;

        cur = head;

        if(index>len-1||index<0) return -1;

        while(cur){

            if(p==index) return cur->val;

            p++;

            cur = cur->next;

        }

        return -1;

    }

    void addAtHead(int val) {

        ListNode* point = new ListNode(val);

        if(!head){

            head = point;

        }else{

            point->next = head;

            head = point;

        }

        //cout<<head->val<<endl;

    }

    void addAtTail(int val) {

        ListNode* point = new ListNode(val);

        if(!head){

            head = point;

            return;

        }//

        ListNode* cur = head;

        while(cur->next){

            cur = cur->next;

        }

        cur->next = point;  

    }

    void addAtIndex(int index, int val) {

        int len = 0;

        int p = 0;

        if(index==0){

            addAtHead(val);

            return;

        }//如果index为0相当于在头节点插入

        ListNode* dummyHead = new ListNode();

        dummyHead->next = head;

        ListNode* cur = dummyHead->next;

        ListNode* pre = dummyHead;

        for(cur=dummyHead->next;cur;cur=cur->next) len++;

        cur = dummyHead->next;

        cout<<len<<endl;

        if(index>len||index<0) return;

        else if(index==len){

            addAtTail(val);

            //cout<<"add:"<<head->next->next->next->val<<endl;

            return;

        }//index为链表长度时,在尾部插入

        while(cur){

            if(index==p){

                ListNode* temp = new ListNode(val);

                pre->next=temp;

                temp->next=cur;

            }

            p++;//下标指针后移

            pre = cur;

            cur=cur->next;

        }

        head = dummyHead->next;

        delete dummyHead;

    }

    void deleteAtIndex(int index) {

        ListNode* dummyHead = new ListNode();

        if(!head){

            return;

        }//判断head节点时候为空

        dummyHead->next = head;

        ListNode* pre = dummyHead;

        ListNode* cur = dummyHead->next;

        int len = 0;

        int p = 0;

        for(cur=dummyHead->next;cur;cur=cur->next) len++;

        cur = dummyHead->next;

        if(index>len-1||index<0) return;

        while(cur){

            if(index==p){

                pre->next = cur->next;

                delete cur;

                break;

            }

            pre = cur;

            cur = cur->next;

            p++;

        }

        head = dummyHead->next;

        delete dummyHead;

    }

};

Leetcode 206 反转链表

题目链接 206. 反转链表
文章链接 https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html
视频链接 https://www.bilibili.com/video/BV1nB4y1i7eL

思路

这道题可以把每个反转的过程分成四步,第一步先记录每个当前节点cur的下一个节点,第二步是将当前节点的next指针指向他的上一个节点pre,第三步是将上一个节点pre更新为当前节点cur,最后一步更新当前节点cur为next

在这里插入图片描述

代码

  • 迭代
 class Solution {

public:

    ListNode* reverseList(ListNode* head) {

        ListNode* dummyHead = new ListNode();

        if(!head||!head->next){

            return head;

        }//注意头节点为空的情况

        dummyHead->next = head;

        ListNode* cur = dummyHead->next;

        ListNode* next = cur;

        ListNode* pre = dummyHead;

        while(cur){//四个步骤

            next = cur->next;

            cur->next = pre;

            pre = cur;

            cur = next;

            //cout<<pre->val<<endl;

        }

        head = pre;

        //cout<<head->val;

        dummyHead->next->next = nullptr;

        delete dummyHead;

        return head;

    }

};

  • 两种递归写法(想不到用递归解法,但是思路很好,搬运过来方便复习)
//从前向后递归(卡哥的)
class Solution {
public:
    ListNode* reverse(ListNode* pre,ListNode* cur){
        if(cur == NULL) return pre;//递归结束条件
        ListNode* temp = cur->next;
        cur->next = pre;
        return reverse(cur,temp);
    }
    ListNode* reverseList(ListNode* head) {
        return reverse(NULL, head);
    }

};
//从后向前(leetcode官方题解)
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        // 边缘条件判断
        if(head == NULL) return NULL;
        if (head->next == NULL) return head;
        
        // 递归调用,翻转第二个节点开始往后的链表
        ListNode *last = reverseList(head->next);
        // 翻转头节点与第二个节点的指向
        head->next->next = head;
        // 此时的 head 节点为尾节点,next 需要指向 NULL
        head->next = NULL;
        return last;
    }
}; 
  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值