LeetCode:经典题之206、92题解及延伸

系列目录

88.合并两个有序数组
52.螺旋数组
567.字符串的排列
643.子数组最大平均数

150.逆波兰表达式
61.旋转链表
160.相交链表
83.删除排序链表中的重复元素

389.找不同
1491.去掉最低工资和最高工资后的工资平均值
896.单调序列

206.反转链表
92.反转链表II

141.环形链表
142.环型链表


目录


206. 反转链表

🌟链表+递归+迭代

原题链接

C++

若未特殊标明,以下题解均写用C++

方法一 迭代
cpp 复制代码
/**
 * 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) {}
 * };
 */

 // 迭代
 // 比较费神hh
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        // presevse 一个 prev指针
        ListNode* prev = nullptr;
        // 定义 curr 让curr移动 curr开始指向"1"
        ListNode* curr = head;
        while (curr != nullptr) {
            // 定义 next 记录当前curr->next值
            ListNode* next = curr->next;
            // step1 让"1"指向空
            // 用完 prev 再改prev
            curr->next = prev;
            prev = curr;
            curr = next;
        }

        // 每次反转 prev都会指向刚刚翻转完的节点
        // 迭代------个人的理解有点类似数学上的"同理可得"
        return prev; 
    }
};
方法二 递归
cpp 复制代码
/**
 * 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) {
        // 链表为空 或 链表长度为1
        if (head == nullptr || head->next == nullptr)
            return head;

        ListNode* newHead = reverseList(head->next);
        head->next->next = head;
        head->next = nullptr;
        
        return newHead;
    }
};

92. 反转链表II

🌟链表+迭代

原题链接

本题有些困难,可以结合上一题多练几遍~
链表的题本身没什么算法上的难度,多画图就好啦

C++

cpp 复制代码
/**
 * 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 {
// 迭代 反转一个链表
private:
    void reveseLinkedList(ListNode* head)
    {
        // 在private 中新定义一个prev 指向空
        ListNode* prev = nullptr;
        ListNode* curr = head;
        
        while (curr != nullptr) {
            ListNode* next = curr->next;
            curr->next = prev;
            prev = curr;
            curr = next;
        }
    }

public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        ListNode* dummy = new ListNode (0, head);
        ListNode* prev = dummy;
        // 让prev 走到 left的前一个节点, 方便一会把反转链表接回来
        // 并定义leftNode
        for (int i = 0; i < left - 1; i ++)
            prev = prev->next;

        // 定义rightNode 让rightNode走到 right
        ListNode* rightNode = prev;
        for (int i = 0; i < right - left + 1; i ++)
            rightNode = rightNode->next;

        // 截取需要反转的链表
        ListNode* leftNode = prev->next;
        ListNode* curr = rightNode->next;

        // 切段 反转链表
        prev->next = nullptr;
        rightNode->next = nullptr;
        
        reveseLinkedList (leftNode);

        // 接回 反转链表
        prev->next = rightNode;
        leftNode->next = curr;   

        return dummy->next;
    }
};
// 注意这个; 分号~

类与结构体

重要区别

  • 类和结构体的最主要的区别 :类默认private,结构体默认public
  • 一般把比较复杂的、代码较长的定义为类class,其余为结构体struct
  • 记得在末尾的闭大括号后加;

区别总结

  1. 默认访问修饰符
    • 类(class)的成员默认是私有的(private)
    • 结构体(struct)的成员默认是公有的(public)
  2. 继承方式
    • 当一个类从另一个类继承时,默认的继承方式是私有继承(private),但通常显式地指定为公有继承(public)、保护继承(protected)或私有继承(private)
    • 结构体不支持继承(在C++中,尽管可以通过某些技巧让结构体看起来像支持继承,但这不是标准用法)
  3. 设计目的
    • 类(class)通常用于封装数据(成员变量)和行为(成员函数),以支持面向对象编程(OOP)的特性,如:封装、继承和多态
    • 结构体(struct)通常用于表示一组数据的集合,这些数据之间可能存在一定的关系,但不一定支持OOP的所有特性 在C++中,结构体也可以具有成员函数和继承特性,但在C语言中,结构体仅用于表示数据的集合
  4. 内存布局
    • 在内存布局上,结构体和类通常是相似的,但具体取决于编译器和类的特定实现(如:是否包含虚函数等)
  5. 语法和语义
    • 从语法上讲,结构体和类在C++中的声明方式非常相似,但它们的语义和用途有所不同
  6. 使用场景
    • 类通常用于设计复杂的、面向对象的系统,其中对象具有明确的状态和行为
    • 结构体通常用于表示简单的数据结构,如:点、矩形、链表节点等
  7. 封装性
    • 类具有更好的封装性,因为它可以隐藏实现细节(通过将成员设置为私有),只暴露必要的公共接口
    • 结构体通常不提供这样的封装性,因为它的成员默认是公有的
  8. 多态性
    • 类支持多态性,这意味着可以通过基类指针或引用来调用派生类的成员函数(如果该函数在基类中被声明为虚函数)
    • 结构体不直接支持多态性,因为它们通常不用于定义类层次结构
  9. 可访问性控制
    • 类可以通过访问修饰符(publicprotectedprivate)来严格控制成员的可访问性
    • 结构体通常只使用public访问修饰符(因为它是默认的),但也可以显式地使用其他访问修饰符

访问修饰符

在C++中,privateprotectedpublic 是三个访问修饰符,用于控制类(class)或结构体(struct)中的成员(包括数据成员和成员函数)的访问权限 这些访问修饰符定义了在类的外部如何与这些成员交互

public(公有的)

  • 如果类的成员被声明为 public,那么它们可以在任何地方被访问
  • 公有成员可以在类的外部直接访问,也可以通过类的对象或指针访问
  • 公有成员通常用于表示类的外部接口,即其他类如何与该类交互

private(私有的)

  • 如果类的成员被声明为 private,那么它们只能在类的内部被访问
  • 私有成员不能通过类的对象或指针从类的外部直接访问
  • 私有成员通常用于隐藏类的内部实现细节,并防止类的用户直接修改类的状态

protected(受保护的)

  • protected 成员在类的内部(包括派生类)可以被访问,但在类的外部(即不是从类直接或间接继承的其他代码)不能直接访问
  • 保护成员通常用于在基类中定义一些可以由派生类访问但不应由类的用户直接访问的成员

示例

cpp 复制代码
class MyClass {  
public:  
    int publicVar; // 公有数据成员  
    void publicFunc() { /* ... */ } // 公有成员函数  
  
protected:  
    int protectedVar; // 受保护数据成员  
    void protectedFunc() { /* ... */ } // 受保护成员函数  
  
private:  
    int privateVar; // 私有数据成员  
    void privateFunc() { /* ... */ } // 私有成员函数  
};  
  
// 访问公有成员  
MyClass obj;  
obj.publicVar = 10;  
obj.publicFunc();  
  
// 下面的行将不会编译,因为它们尝试访问私有和受保护的成员  
// obj.privateVar = 20; // 错误:无法访问私有成员  
// obj.protectedVar = 30; // 错误:无法访问受保护成员  
// obj.privateFunc(); // 错误:无法访问私有成员函数  
// obj.protectedFunc(); // 错误:无法访问受保护成员函数
相关推荐
爱学习的大牛12315 分钟前
通过vmware虚拟机安装和调试编译好的 ReactOS
c++·windows内核
dal118网工任子仪15 分钟前
web安全漏洞之ssrf入门
笔记·学习·计算机网络·网络安全
键盘敲没电25 分钟前
【iOS】知乎日报前三周总结
学习·ios·objective-c·xcode
Lyqfor35 分钟前
云原生学习
java·分布式·学习·阿里云·云原生
Dontla1 小时前
Rust泛型系统类型推导原理(Rust类型推导、泛型类型推导、泛型推导)为什么在某些情况必须手动添加泛型特征约束?(泛型trait约束)
开发语言·算法·rust
大懒的猫猫虫1 小时前
Upload-Labs-Linux1学习笔迹 (图文介绍)
学习
Ttang231 小时前
Leetcode:118. 杨辉三角——Java数学法求解
算法·leetcode
喜欢打篮球的普通人1 小时前
rust模式和匹配
java·算法·rust
java小吕布1 小时前
Java中的排序算法:探索与比较
java·后端·算法·排序算法