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

文章介绍了链表的基本概念,包括单链表的定义和构造函数的使用。讨论了203题的移除链表元素方法,强调了使用虚拟头结点和释放内存的重要性。接着,文章探讨了707题设计链表时结构体的位置对编译的影响,解释了访问控制在C++类中的作用,并给出了添加、删除和获取链表元素的实现。此外,文章还提到了206题反转链表的双指针和递归解法。
摘要由CSDN通过智能技术生成

day3

链表理论基础

链表的定义关注一下(可能是自己c++就没啥底子导致的吧,struct和class的特性并不熟)

// 单链表
struct ListNode {
    int val;  // 节点上存储的元素
    ListNode *next;  // 指向下一个节点的指针
    ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
};

这里不定义构造函数是可以的,C++默认生成一个构造函数。 但是卸了之后,就不会默认生成了。

203.移除链表元素

无大问题,使用一个虚拟头结点比较方便,再就是注意delete掉废弃的结点,释放内存空间。

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* pre = new ListNode(0, head);
        ListNode* p = pre;
        while(p->next) {
            if(p->next->val == val) {
                p->next = p->next->next;
            }
            else p = p->next;
        }
        return pre->next;
    }
};

707.设计链表

这种设计题像写作文,真正检验对一个知识的认知。

并且遇到一个问题:

如果struct ListNode定义在private里,程序没问题:

请添加图片描述

但是放到public里,就会报错,
请添加图片描述

请添加图片描述

这是因为c++的编译问题吗?

最后发现,是ListNode的使用在其声明前面,然而力扣c++编译器的报错跟这个不太沾边。至于c++编译是先private还是public,也不知道了。

class MyLinkedList {
private:
    // 这里如何定义好像还不会
    struct ListNode{
        int val;
        ListNode* next;
        ListNode(int x) : val(x), next(nullptr) {}
    };

    int size;
    ListNode* pre;

public:
    MyLinkedList() {
        pre = new ListNode(0);
        size = 0;
    }
        
    // void print() {
    //     ListNode* p = pre->next;
    //     while(p) {
    //         cout << p->val << "->";
    //         p = p->next;
    //     }
    //     cout << endl; 
    // }

    int get(int index) {
        ListNode* p = pre->next;
        int i = 0;
        for( ; i < index && p; i++) {
            p = p->next;
        }
        if(p) return p->val;
        else return -1;
    }
    
    void addAtHead(int val) {
        ListNode* tmp = new ListNode(val);
        tmp->next = pre->next;
        pre->next = tmp;
        // print();
    }
    
    void addAtTail(int val) {
        ListNode* p = pre;
        ListNode* tmp = new ListNode(val);
        while(p->next) p = p->next;
        p->next = tmp;
    }
    
    void addAtIndex(int index, int val) {
        ListNode* tmp = new ListNode(val);
        if(index < 0) {
            tmp->next = pre->next;
            pre->next = tmp;
        }
        int i = 0;
        ListNode* p = pre;
        while (p->next && i < index) {
            i++;
            p = p->next;
        }
        if(i == index) {
            tmp->next = p->next;
            p->next = tmp;
        }
        // print();
        return;
    }
    
    void deleteAtIndex(int index) {
        ListNode* p = pre;
        int i = 0;
        while(p->next && i < index) {
            i++;
            p = p->next;
        }
        if(i == index && p->next) {
            ListNode* tmp = p->next;
            p->next = p->next->next;
            delete tmp;
        }
        return;
    }
};

卡哥的答案还没细看

另外,关于c++中public、private、proteced等,我觉得百度知道上的这个比喻很好:

C++中private和public都可以先写。
private和public的作用是让编译器帮你检查某些模块是否使用了他没权限使用的模块,也就是生成可执行代码的时候做权限检查。比如,公司里各个部门有自己私有的信息,财务部可以看所有员工工资,而销售部不可以,普通员工也不可以。
可不可以访问都是认为规定的,而且在写代码的时候程序是不会执行的,因此需要在生成代码的时候做一些检查,就像语法错误在编译的时候被检查出来一样,因为人规定了代码该如何写。访问控制也是在编译的时候检查,c++采用了private,public,protected,以及friend来限制访问权限。
private的意思是指类的内部变量或者函数是私有的,在类之外包括继承类就不可见,像魔术师的道具;public是指类的内部变量是外部可见的,像魔术师的表演;protected是指除了本类和继承类之外不可见,像魔术师希望徒弟使用道具,就得让其徒弟看见道具,但是是一种受保护的权限;friend是指特定指出哪些类或者模块可以看见本类的私有(private以及protected)成员,这就是魔术师信得过的朋友可以让他看见一些幕后。
使用好这个规则,只要程序中出现了越权访问的代码,编译的时候就会被检查出来,以保证安全。
举例:

class moshushi//魔术师类
{
friend class daoyan;//导演可以知道魔术师背后的秘密

public://所有人都可以看见的行为以及物品
    int jinchang();//进场
    int biaoyan();//表演
    int tuichang();//退场
    int shou, yifu, maozi;//手,衣服,帽子

protected://徒弟可以知道的
    int zhaotuo();//找个托
    int gangsi;//钢丝

private://只有自己和friend可以知道
    int zuobi();//作弊
    int yaoshui, tezhizhuozi;//药水,特制桌子
};

class tudi: public moshushi魔术师徒弟
{
    //自动有了魔术师的public以及protected
};

class daoyan导演
{
    int func(){
        //可以访问到魔术师对象的私有域
    }
    //...
};

class guanzhong观众
{
    //不能访问魔术师对象的私有域
    //...
}; 

206.反转链表

双指针法,脑子里想有点难度,画图容易解决(其实加上tmp是三指针)

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

递归法之前做过,这次没写;

用栈也是很有意思的思路,这次写了一下,stack的基础语法还不熟(初始化、判断栈空不能看top()是否为空,而是empty()

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (!head || !head->next) return head;
        stack<ListNode*> st;
        while (head) {
            st.push(head);
            head = head->next;
        }
        ListNode* rHead = st.top();
        ListNode* cur = rHead;
        st.pop();
        // printf("are you ok?\n");
        while (!st.empty()) {
            cur->next = st.top();
            st.pop();
            cur = cur->next;
        }
        cur->next = nullptr;
        return rHead;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值