203.移除链表元素
链接
(1)文字讲解:https://programmercarl.com/0203.移除链表元素.html#思路
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/remove-linked-list-elements/
未看题解的想法
没有想到头节点需要特殊对待
看题解后的想法
1.首先制造一个虚拟头节点,因为如果头节点的值就是val,简单地delete之后,就会找不到剩下的链表元素
2.其次链表删除的操作是这样的:使得该节点的上一个节点的next指向这个节点的next
本题难点
1.理解虚拟头节点
2.自己定义ListNode结构体
代码
/**
* 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) {}
* };
*/
// 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* removeElements(ListNode* head, int val) {
ListNode* new_head = new ListNode(-1, head);
// new_head->next = head;
ListNode* cur = new_head;
while(cur->next != NULL){
if(cur->next->val == val){
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}else{
cur = cur->next;
}
}
ListNode* real_head = new_head->next;
delete new_head;
return real_head;
}
};
707.设计链表
链接
(1)文字讲解:https://programmercarl.com/0707.设计链表.html
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/design-linked-list/description/
未看题解的想法
1.经过链表基础,对于虚拟头节点已经理解。
2.但是两个地方错了。
(1)get函数
int get(int index) {
if(index > (size-1)){
return -1;
}
ListNode * cur = new_head;
while(index--){
cur = cur->next;
}
return cur->val;
}
这里的index是下标,加了虚拟头节点之后,链表下标会➕1,所以比较不合理的index的时候,比较的还是size-1,但是在设置cur的初始值的时候,要设置为new_head->next,而不是上面错误代码中的new_head。
(2)addAtIndex函数
void addAtIndex(int index, int val) {
if(index > (size-1)){
return;
}
ListNode* ind_node = new ListNode(val);
ListNode* cur = new_head;
while(index--){
cur = cur->next;
}
ind_node->next = cur->next;
cur->next = ind_node;
size++;
}
这里的index是要在这个位置之前加上一个元素,但是链表里加元素,其实重要的是要得到这个index之前的索引(因为你需要改index之前的元素的next)。而且这里的index可以取到size,代表在尾部加,所以比较index合理性的时候要注意,小于等于size-1就行。cur的取值就可以取new_head,因为虚拟头节点的加入,每个元素的index都加一,但是我们这里本来就是要取之前的一个元素,所以从new_head开始取刚好。
看题解后的想法
如上,修改了两个错误的函数取值。
注意虚拟头节点的加入对于index的影响。
本题难点
1.虚拟头节点
2.index变化
代码
class MyLinkedList {
public:
struct ListNode{
int val;
ListNode* next;
ListNode(int val): val(val), next(nullptr){}
};
MyLinkedList() {
new_head = new ListNode(0);
size = 0;
}
int get(int index) {
if(index > (size-1)){
return -1;
}
ListNode * cur = new_head->next;
while(index--){
cur = cur->next;
}
return cur->val;
}
void addAtHead(int val) {
ListNode* tmp = new ListNode(val);
tmp->next = new_head->next;
new_head->next = tmp;
size++;
}
void addAtTail(int val) {
ListNode * cur = new_head;
while(cur->next){
cur = cur->next;
}
ListNode* tail_node = new ListNode(val);
cur->next = tail_node;
size++;
}
void addAtIndex(int index, int val) {
if(index > size){
return;
}
ListNode* ind_node = new ListNode(val);
ListNode* cur = new_head;
while(index--){
cur = cur->next;
}
ind_node->next = cur->next;
cur->next = ind_node;
size++;
}
void deleteAtIndex(int index) {
if(index > (size-1)){
return;
}
ListNode* cur = new_head;
while(index--){
cur = cur->next;
}
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
size--;
}
private:
ListNode * new_head;
int size;
};
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList* obj = new MyLinkedList();
* int param_1 = obj->get(index);
* obj->addAtHead(val);
* obj->addAtTail(val);
* obj->addAtIndex(index,val);
* obj->deleteAtIndex(index);
*/
206.反转链表
链接
(1)文字讲解:https://programmercarl.com/0206.翻转链表.html#思路
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/reverse-linked-list/
未看题解的想法
/**
* 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) {}
* };
*/
// struct ListNode{
// int val;
// ListNode *next;
// ListNode(): val(0), next(nullptr){}
// ListNode(int val): val(val), next(nullptr){}
// ListNode(int val, ListNode *next): val(val), next(next){}
// };
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode *pre = new ListNode();
ListNode *cur = head;
while(cur->next){
ListNode *temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
cur->next = pre;
return cur;
}
};
两个问题:
(1)while(cur->next)
一开始,也想写while(cur),但是我突然脑子短路了,因为最后需要return 头节点,但是如果这样写,退出循环的时候cur是空节点,所以我就写了cur->next,这样退出循环的时候是尾节点,然后处理一下让他指向pre就行。但是,会报错runtime error: member access within null pointer of type ‘ListNode’ (solutio 我输出了一下,很奇怪,到了cur为尾节点的时候就应该退出循环,但是不仅没有退出,next还指向了一个奇怪的地址,我现在还是没搞明白,但是估计和leetcode环境有关。
(2) ListNode *pre = new ListNode()
这样的初始化会使得反转后的链表尾节点多一个0
看题解后的想法
1.反转链表就是改变next的指向,中间用tmp记录一下原来的next地址,方便遍历
2.ListNode可以直接赋值为NULL
3.可以直接用while(cur)来做循环,然后return pre。这个就不会出现尾节点的next随便指向的问题,很奇怪
本题难点
理解虚拟头节点
代码
版本一
/**
* 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) {}
* };
*/
// struct ListNode{
// int val;
// ListNode *next;
// ListNode(): val(0), next(nullptr){}
// ListNode(int val): val(val), next(nullptr){}
// ListNode(int val, ListNode *next): val(val), next(next){}
// };
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode *pre = NULL;
ListNode *temp = NULL;
ListNode *cur = head;
while(cur){
temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
};
版本二:正向递归
/**
* 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) {}
* };
*/
// struct ListNode{
// int val;
// ListNode *next;
// ListNode(): val(0), next(nullptr){}
// ListNode(int val): val(val), next(nullptr){}
// ListNode(int val, ListNode *next): val(val), next(next){}
// };
class Solution {
public:
ListNode* reverse(ListNode* pre, ListNode* cur){
if(cur == NULL) return pre;
ListNode* tmp = cur->next;
cur->next = pre;
return reverse(cur, tmp);
}
ListNode* reverseList(ListNode* head) {
return reverse(NULL, head);
}
};
版本三:反向递归
/**
* 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) {}
* };
*/
// struct ListNode{
// int val;
// ListNode *next;
// ListNode(): val(0), next(nullptr){}
// ListNode(int val): val(val), next(nullptr){}
// ListNode(int val, ListNode *next): val(val), next(next){}
// };
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == NULL) return NULL;
if (head->next == NULL) return head;
// 这个函数的目的就是要找到尾节点,找到了之后,就开始从后往前反转
ListNode *last = reverseList(head->next);
// 使得next的next指向自己(完成反转)
head->next->next = head;
// 这个是为了保证翻到最后一个(头节点)的时候他指向NULL
head->next = NULL;
// 返回反转后的头节点(原来的尾节点,这就是为啥每次递归都要return last)
return last;
}
};