每日计划-1116
1. 完成 234. 回文链表
class Solution {
public:
bool isPalindrome(ListNode* head) {
if (head == nullptr || head->next == nullptr)
return true;
// 使用快慢指针找到中点
ListNode* slow = head;
ListNode* fast = head;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
// 反转后半部分
ListNode* prev = nullptr;
while (slow != nullptr) {
ListNode* nextTemp = slow->next;
slow->next = prev;
prev = slow;
slow = nextTemp;
}
// prev 现在是反转后半部分的头
ListNode* left = head;
ListNode* right = prev;
// 比较左右部分
while (right != nullptr) {
if (left->val != right->val) {
return false;
}
left = left->next;
right = right->next;
}
return true;
}
};
2. 八股部分
1)C/C++ 中有哪些类型转换方式? 分别有什么区别?
static_cast:用于非多态类型地转换
dynamic_cast:用于多态类型的转换,主要用于向下转换类型(从基类指向派生类的指针/引用),会检查转换的有效性,如果转化不安全,择无法转换。
Const_cast:用于去除 const 属性只能用于指针或者引用。
reinterpret_cast:用于将任何指针类型,转换成任何其他的指针类型,可能也包括指针与足够大的整数类型之间的转换。
#include<iostream>
using namespace std;
int main() {
double a = 3.14;
int i = static_cast<int>(a);
cout << i << endl;
class Base {
virtual void dummy() {}
};
class Deriverd :public Base {};
Base* b = new Deriverd();
Deriverd* d = dynamic_cast<Deriverd*>(b);
cout << d<<endl;
const int e = 10;
int* nowint = const_cast<int*>(&e);
cout << e<<endl;
//C++ 的动态类型识别 (RTTI) 通过 dynamic_cast 来进行类的类型转换
int* p = new int(65);
char* ch = reinterpret_cast<char*>(p);//convert int* to char*
cout << *ch<<endl;
}
2) 类型转换可能会带来哪些问题?
- 数据丢失
- 原因:当把一个表示范围较大的数据类型转换为表示范围较小的数据类型时,可能会丢失数据。例如,将一个
double
类型的值转换为int
类型,小数部分会被截断。 - 例子:
double d = 3.99; int i = (int)d;
,这里i
的值为 3,小数部分的 0.99 丢失了。
- 原因:当把一个表示范围较大的数据类型转换为表示范围较小的数据类型时,可能会丢失数据。例如,将一个
- 精度降低
- 原因:在一些数值转换中,即使没有数据丢失,也可能会降低精度。比如将一个高精度的数据类型转换为低精度的数据类型。
- 例子:将
long double
类型转换为float
类型,long double
可能具有更高的精度来表示小数,转换后可能无法精确表示原来的值。
- 指针转换导致的错误
- 原因:
- 在指针类型转换中,如果不谨慎,可能会导致访问非法内存地址。例如,使用
reinterpret_cast
或者不恰当的C
风格强制类型转换,将一个指针转换为不相关类型的指针后进行访问。 - 当转换后的指针类型所期望的内存布局和实际内存布局不符时,也会出错。
- 在指针类型转换中,如果不谨慎,可能会导致访问非法内存地址。例如,使用
- 例子:
- 假设
struct A {int a;}; struct B {double b;}; A a; B* b = reinterpret_cast<B*>(&a);
,此时如果通过b
来访问成员b
,就会出现错误,因为a
和b
的内存布局完全不同,按照B
的结构来访问a
的内存是非法的。
- 假设
- 原因:
- 对象切片(Object Slicing)
- 原因:在 C++ 中,当把派生类对象赋值给基类对象时,如果是通过值传递(不是指针或引用),会发生对象切片。这是因为派生类对象包含了基类部分和派生类特有的部分,当以值传递方式赋值给基类对象时,只会复制基类部分,而切掉了派生类特有的部分。
- 例子:
- 假设
class Base {public: int baseData;}; class Derived : public Base {public: int derivedData;};
,Derived d; Base b = d;
,这里b
只包含了d
中的baseData
部分,derivedData
部分被切掉了,这可能会导致意外的行为,尤其是当存在虚函数等多态特性时。
- 假设
- 违反类型系统的语义规则
- 原因:例如通过
const_cast
去除const
属性后修改了本来不应该修改的值,这违反了const
的语义,会使程序的行为难以预测。 - 例子:在一个函数中接收一个
const
参数,本意是保证参数在函数内部不被修改,但如果使用const_cast
去除const
属性并修改了参数,可能会导致调用该函数的其他部分出现错误,因为它们可能依赖于参数的const
性质。
- 原因:例如通过