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;
}
};