当前位置: 首页 > article >正文

力扣 回文链表-234

回文链表-234

const int N = 1e5+5;
int a[N];//定义一个整形的全局数组作为辅助数组存储链表反转前的值
class Solution {
/*本题的解题思路是先将链表中每个值存储到辅助数组a中,然后反转链表,
最后,反转后链表的值和没反转之前的值(存在辅助数组中的值)一一作比较,
如果每个值都相同则为回文链表返回true,否则返回false*/
public:
int i = 0;//i作为循环中数组的下标
    bool isPalindrome(ListNode* head) {
        //先将头节点head的位置存储起来,因为循环存储链表反转前的值时,head的位置会发生变化,就无法进行后续反转链表操作了
        ListNode* originalHead = head;
        //将链表中的每个节点的值存储到数组a中
        while(head!=NULL)
        {
            a[i] = head->val;
            head = head->next;
            ++i;
        }
        //以下是反转链表操作
        ListNode* cur = NULL;//定义一个ListNode类型的指针指向头节点的左一个位置,作为反转后链表的结尾
        ListNode* pre = originalHead;//定义一个ListNode类型的指针指向头节点位置
        //while循环当pre指向最后一个节点的右一个节点(NULL)时,全部反转完成,cur正好指向最后一个节点作为反转后的头节点
        while(pre!=NULL)
        {
            //定义一个ListNode类型的指针t用来存储指针pre指向的下一个位置以便在修改当前节点的指针后能够继续遍历链表
            ListNode* t = pre->next;
            //进行局部反转,将pre的下一个节点改为指向上一个节点(cur)
            pre->next = cur;
            //局部反转过后进行右移,下一次循环之后继续pre,cur两个指针进行局部反转
            cur = pre;
            //局部反转后pre也进行右移,始终保持cur在左pre在右
            pre = t;
            //注意:如果不将pre的下一个节点存储在t中,那么在经过pre->next = cur后就无法再访问到原来的下一个节点了。
        }
        /*最后反转前的链表每个节点的值(存放在数组a中)与反转后链表每个节点的值作比较,
        只要遇到不同的就直接返回false,如果一直到循环结束都没遇到不同的值,则返回true*/
        for(int j = 0;j < i;j++)
        {
            if(cur->val!=a[j])return false;
            cur = cur->next;
        }
        return true;
    }
};

每日问题

C C++ 中有哪些类型转换方式? 分别有什么区别?

1.隐式类型转换(自动类型转换)

定义:这是编译器自动进行的类型转换,不需要程序员显示地操作。它主要遵循一定的规则,在不丢失数据精度(或者在合理范围内丢失精度)的情况下,将一种数据类型转换为另一种数据类型。

转换规则示例:

算数运算中的转换:在进行算数运算时,如果操作数类型不同,编译器会自动进行转换。例如,在int + double的运算中,int类型的值会自动转换为double类型,然后进行加法运算。像3+3.5,编译器会将3转换为double类型的3.0,再和3.5相加,结果为6.5.

赋值运算中的转换:当把一个值赋给一个变量时,如果值的类型和变量类型不一致,也可能发生隐式转换。例如,将一个int值赋给一个double变量,int值会自动转换为double类型。如double d = 5;,这里5会自动转换为5.0后赋给d。但是,将一个较大范围类型的值赋给一个较小范围类型的变量时,可能会丢失数据精度,如int i = 3.9;,此时3.9会被截断为3赋给i。

特点:

便利性:隐式转换使得代码编写更加方便,程序员不需要手动处理很多常见的类型转换情况,编译器会自动按照规则进行处理。

潜在风险:可能会导致数据精度丢失或不符合预期的结果。特别是在涉及不同的混合运算和赋值时,需要注意数据类型的范围和精度变化。

2.显示类型转换(强制类型转换)

        定义:这是程序员通过特定的语法手动进行的类型转换,用于再需要明确改变数据类型的情况下使用。

C语言中的强制类型转换方式:

        基本语法:使用(目标类型)表达式的形式,例如,(int)3.14会将3.14强制转换为int类型,结果为3。

        指针类型转换示例:在C语言中,还可以进行指针类型的强制转换。例如,假设有一个void*类型的指针void* p;,如果想将它转换为int*类型,可以使用(int*)p。但这种转换需要谨慎,因为如果转换不当可能会导致程序出错,如访问非法内存等情况。

这是最通用的类型转换方式,适用于所有基本数据类型和指针类型。但它也是最不安全的,因为它会进行尽可能宽松的转换,不考虑类型之间的兼容性和潜在的数据丢失。

C++语言中的强制类型转换方式(更安全和明确的方式):
1.静态类型转换(Static Case):

语法:static_cast(expression)

静态类型转换用于在具有明确、安全的转换路径的类型之间进行转换。它同通常用于基本数据类型之间的转化、相关类之间的转换(如基类与派生类之间的转换,前提是转换时安全的),以及void* 与其他指针类型之间的转换。

double a = 100.5;
int b = static_cast<int>(a);//将double转换为int,可能丢失小数部分
2.动态类型转换(Dynamic Cast)

语法:dynamic_cast(expression)

动态类型转换用于在运行时检查类对象的实际类型,并安全地向上或向下的类层次结构转换。它主要用于多态类型(即包含虚函数的类)。如果转换失败,dynamic_cast会返回nullptr(对于指针)或抛出std::bad_cast异常(对于引用)。

class Base{ virtual void func(){}};
class Derived : public Base{};

Base* basePtr = new Derived();
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);//将Base*转换为Derived*
3.常量类型转换(Const Cast)

语法:const_cast(expression)

常量类型转换用于去除或添加常量性(const 或 volatile)。它主要用于将 const 指针转换为非 const 指针(或反之),以便能够修改原本不可修改的数据。

const int* constPtr = &someValue;
int* nonConstPtr = const_cast<int*>(constPtr);//去除 const 属性
4.重解释类型转换(Reinterpret Cast)

语法:reinterpret_cast(expression)

重解释类型转换用于进行最低级别的转换,它基本上只是重新解释位模式。这种转换通常是不安全的,因为它几乎不进行任何检查,只是简单地告诉编译器将一种类型视为另一种类型。它主要用于底层编程(如与硬件接口)和与C代码的互操作。

最低级别的转换:

reinterpret_cast提供了C++中最低级别的类型转换能力。它几乎不进行任何类型检查,只是简单地告诉编译器:“我知道我在做什么,请把这个指针或引用当作另一种类型来处理。”

重新解释位模式:

当使用reinterpret_cast进行转换时,原始数据的位模式保持不变。这意味着,如果原始数据是以一种类型存储的,而转换后的类型以不同的方式解释这些位,那么得到的结果可能是完全不可预测的。

位模式:位模式,又称位流或位序列,是计算机内部数据的一种表示方式。它由一系列的二进制位(bit)组成,每个位只能是0或1。这些二进制位按照特定的顺序排列,形成了可以表示各种数据类型的位模式。

位模式数据表示:不同的位模式可以表示不同的数据类型,如整数、实数、字符等。通过特定的编码方式,位模式还可以表示更复杂的数据结构,如结构体、联合体等。

位模式应用:数据类型转换:在编程中,有时需要将一种数据类型的变量转换为另一种数据类型。这时,可以通过重新解释位模式的方式来实现类型转换。但需要注意的是,这种转换可能会导致数据丢失或精度下降,因此在使用时需要谨慎。

int a = 100;
void* ptr = &a;
int* intPtr = reinterpret_cast<int*>(ptr);//将 void* 转换为 int*
区别总结:

C风格的强制类型转换:通用但不安全,会进行尽可能宽松的转换。

静态类型转换:在编译时进行,用于明确且安全的类型转换。

动态类型转换:在运行时进行,用于多态类型的向上或向下转换,提供安全类型检查。

常量类型转换:用于添加或去除常量性(const 或 volatile)。

重解释类型转换:最低级别的转换,只是重新解释位模式,通常不安全。

选择哪种类型转换方式取决于具体的场景和安全性要求。在可能的情况下,应优先使用更安全的类型转换方式(如 static_cast 和 dynamic_cast),并尽量避免使用 C 风格的强制类型转换和 reinterpret_cast。

类型转换可能会带来哪些问题?

一、数据丢失

原因:一种数据类型的范围可能比另一种数据类型小。在将一个范围较大的数据类型转换为一个范围较小的数据类型时,超出目标类型表示范围的数据将被截断或丢弃。

示例:将一个浮点数转换为整数时,小数部分将被截断。将一个长字符串转换为一个短的VARCHAR类型时,超出长度的部分将被丢弃。

二、精度问题

原因:在进行数值类型的转换时,特别是从高精度类型向低精度类型转换时,精度可能会受到影响。

示例:将一个DECIMAL类型转换为FLOAT类型时,由于浮点数的二进制表示法无法准确地表示某些十进制小数,可能会导致精度丢失。

三、内存溢出

原因:在进行强制类型转换时,如果目标类型的内存表示比源类型大,而分配的内存不足以容纳转换后的数据,可能会导致内存溢出。

示例:在某些情况下,将一个较小的数据类型转换为较大的数据类型时,如果内存管理不当,可能会引发内存溢出错误。

四、运行时错误

原因:强制类型转换可能会引发运行时错误,特别是在类型之间存在不兼容的情况下。

示例:试图将一个类型转换为与其不兼容的类型时,将会引发异常或错误,并导致程序中断。例如,将一个字符串强制转换为整数时,如果字符串中包含非数字字符,转换将失败并抛出异常。

五、逻辑错误

原因:在进行类型转换时,如果开发者没有正确理解数据类型之间的关系或转换规则,可能会导致逻辑错误。

示例:错误地假设类型转换后的数据具有与原始数据相同的含义或行为,从而在程序中引入逻辑错误。

六、代码可读性降低

原因:过多地使用强制类型转换可能会降低代码的可读性,使代码变得难以理解和维护。

示例:当代码中存在大量的强制类型转换时,读者可能难以理解其含义和目的,从而增加程序的调试难度和维护成本。

七、安全性问题

SQL注入:在数据库操作中,从用户输入或其他不可信的来源获取数据时,不安全的类型转换可能导致SQL注入攻击。

代码注入:在动态生成代码时,不安全的类型转换可能导致代码注入攻击。


http://www.kler.cn/a/397333.html

相关文章:

  • 【机器学习导引】ch6-支持向量机
  • 我的第一个PyQt5程序
  • 基于Matlab的碎纸片的自动拼接复原技术
  • 2、开发工具和环境搭建
  • Essential Cell Biology--Fifth Edition--Chapter one (6)
  • vue3:computed
  • LLMs之Agent:Magentic-One的简介、安装和使用方法、案例应用之详细攻略
  • 最终用途声明
  • 【C#】C#编程入门指南:构建你的.NET开发基础
  • 网络设备驱动与网络子系统,有区别吗?
  • Python 打包教程:从零开始构建可分发的Python包
  • 【ORACLE战报】2024年10月OCP考试战报
  • 在使用 Navicat 操作 MongoDB 时,进行 CRUD(创建、读取、更新、删除)操作的基本语法如下:
  • 《操作系统 - 清华大学》3 -3:连续内存分配:内存碎片与分区的动态分配
  • 机器学习day3-KNN算法、模型调优与选择
  • 【GeekBand】C++设计模式笔记11_Builder_构建器
  • java Collections 详解
  • 第22章 企业级Docker虚拟化平台实战
  • Java StringBuilder详解
  • 数据结构《栈和队列》
  • 针对git、giteeVSCode连接的使用 || Live Share插件使用
  • 最新U盘PE启动安装Win10/Win11系统教程
  • 数据结构(初阶4)---循环队列详解
  • Oracle OCP认证考试考点详解082系列22
  • 正确使用primefaces的process和update
  • elementPlus + table 树形懒加载,子节点的刷新