代码随想录算法训练营第三天|Leetcode 203 移除链表元素,707 设计链表, 206反转链表
Leetcode 203 移除链表元素
题目链接 203.移除链表元素
文章链接 https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html
视频链接 https://www.bilibili.com/video/BV18B4y1s7R9
思路
这道题本质就是链表的删除操作,链表删除时要考虑满足条件的点是头结点的情况。我是对原始链表直接操作的,看了卡哥的讲解之后,可以定义一个虚拟头节点,其实就是把原来的头节点当作普通节点,这样就不用多判断一次,代码看起来也比较舒服一些。最重要的还是链表删除时将前一个节点指向当前节点(满足条件的点,用temp临时存储)的下一个节点,并释放temp
代码
- 对原始链表操作
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* cur = head;
ListNode* pre = nullptr;
while(cur){
if(cur->val==val){
ListNode* temp = cur;
cur = cur->next;
if(!pre){//当前满足条件的点是头节点的情况
head = cur;
delete temp;
}else{
pre->next = cur;
delete temp;
}
}else{
pre = cur;
cur = cur->next;
}
}
return head;
}
};
- 虚拟头节点
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyHead = new ListNode(-1);//定义虚拟头节点,省去判断满足条件的点是否为头节点的步骤
dummyHead->next = head;
ListNode* cur = dummyHead->next;//定义当前节点
ListNode* pre = dummyHead;//定义当前节点的上一个节点
while(cur){
if(cur->val==val){
ListNode* temp = cur;//当前节点满足条件,用临时节点存储并释放
cur = cur->next;
pre->next = cur;//让上一个节点指向当前节点的下一个节点
delete temp;//释放临时节点,也就是满足条件的当前节点
continue;
}else{
pre = cur;
cur = cur->next;
}
}
head = dummyHead->next;
delete dummyHead;//最好把虚拟头节点释放,节省不必要的内存空间
return head;
}
};
Leecode 707 设计链表
题目链接 707. 设计链表
文章链接 https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html
视频链接 https://www.bilibili.com/video/BV1FU4y1X7WD
卡哥讲解虚拟头节点(虽然会占用一些空间,但写起来会方便很多) https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html
思路
这道题考的可太全面了,单把每个函数拿出来其实就是基本的链表的操作,但是放在一起时,每个函数都要先判断head是否为空,不为空的话就是单纯的链表操作了。我也是写了很久,一些操作比如说计算长度,定义虚拟头节点重复好多次,费时间和空间,贡献了leetcode用时最长的解法(放在下面,记录一下自己最开始的想法)。
- 优化
class MyLinkedList {
public:
struct ListNode{//构造一个链表
int val;
ListNode* next;
ListNode(int x):val(x),next(nullptr){}
};
MyLinkedList() {
_dummyHead = new ListNode(0);//初始化虚拟头节点
_size = 0;
}
int get(int index) {
if((index>_size-1)||(index<0)){//index不满足条件退出
return -1;
}
ListNode* cur = _dummyHead->next;
while(index--){
cur = cur->next;
}
return cur->val;
}
void addAtHead(int val) {
ListNode* point = new ListNode(val);
ListNode* cur = _dummyHead;
point->next = _dummyHead->next;//如果head为空,也就是point->next=nullptr,相当于head节点,就不用多判断一次head的条件
_dummyHead->next = point;
_size++;
}
void addAtTail(int val) {
ListNode* point = new ListNode(val);
ListNode* cur = _dummyHead;
while(cur->next){//到链表的最后一个位置截至
cur = cur->next;
}
cur->next = point;
_size++;
}
void addAtIndex(int index, int val) {
if((index>_size)||(index<0)){
return;
}else if(index==_size){
addAtTail(val);
return;
}else{
ListNode* cur=_dummyHead->next;
ListNode* pre=_dummyHead;//当前节点的前一个结点
while(index--){
pre = cur;
cur = cur->next;
}
ListNode* point = new ListNode(val);
point->next = cur;
pre->next = point;
_size++;
}
return;
}
void deleteAtIndex(int index) {
if((index>_size-1)||(index<0)) return;
ListNode* pre = _dummyHead;
ListNode* cur = _dummyHead->next;
while(index--){
pre = cur;
cur = cur->next;
}
pre->next = cur->next;
delete cur;
_size--;
}
private:
ListNode* _dummyHead;//虚拟头节点,私有成员变量最好加上'_'
int _size;//链表大小
};
- 原始代码
class MyLinkedList {
public:
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){}
};
ListNode* head = nullptr;//初始化head节点为空
MyLinkedList() {
}
int get(int index) {
int len = 0;
int p = 0;
if(!head){
return -1;
}//判断head节点是否为空
ListNode* cur = head;
for(cur=head;cur;cur=cur->next) len++;
//cout<<len<<endl;
cur = head;
if(index>len-1||index<0) return -1;
while(cur){
if(p==index) return cur->val;
p++;
cur = cur->next;
}
return -1;
}
void addAtHead(int val) {
ListNode* point = new ListNode(val);
if(!head){
head = point;
}else{
point->next = head;
head = point;
}
//cout<<head->val<<endl;
}
void addAtTail(int val) {
ListNode* point = new ListNode(val);
if(!head){
head = point;
return;
}//
ListNode* cur = head;
while(cur->next){
cur = cur->next;
}
cur->next = point;
}
void addAtIndex(int index, int val) {
int len = 0;
int p = 0;
if(index==0){
addAtHead(val);
return;
}//如果index为0相当于在头节点插入
ListNode* dummyHead = new ListNode();
dummyHead->next = head;
ListNode* cur = dummyHead->next;
ListNode* pre = dummyHead;
for(cur=dummyHead->next;cur;cur=cur->next) len++;
cur = dummyHead->next;
cout<<len<<endl;
if(index>len||index<0) return;
else if(index==len){
addAtTail(val);
//cout<<"add:"<<head->next->next->next->val<<endl;
return;
}//index为链表长度时,在尾部插入
while(cur){
if(index==p){
ListNode* temp = new ListNode(val);
pre->next=temp;
temp->next=cur;
}
p++;//下标指针后移
pre = cur;
cur=cur->next;
}
head = dummyHead->next;
delete dummyHead;
}
void deleteAtIndex(int index) {
ListNode* dummyHead = new ListNode();
if(!head){
return;
}//判断head节点时候为空
dummyHead->next = head;
ListNode* pre = dummyHead;
ListNode* cur = dummyHead->next;
int len = 0;
int p = 0;
for(cur=dummyHead->next;cur;cur=cur->next) len++;
cur = dummyHead->next;
if(index>len-1||index<0) return;
while(cur){
if(index==p){
pre->next = cur->next;
delete cur;
break;
}
pre = cur;
cur = cur->next;
p++;
}
head = dummyHead->next;
delete dummyHead;
}
};
Leetcode 206 反转链表
题目链接 206. 反转链表
文章链接 https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html
视频链接 https://www.bilibili.com/video/BV1nB4y1i7eL
思路
这道题可以把每个反转的过程分成四步,第一步先记录每个当前节点cur的下一个节点,第二步是将当前节点的next指针指向他的上一个节点pre,第三步是将上一个节点pre更新为当前节点cur,最后一步更新当前节点cur为next
代码
- 迭代
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* dummyHead = new ListNode();
if(!head||!head->next){
return head;
}//注意头节点为空的情况
dummyHead->next = head;
ListNode* cur = dummyHead->next;
ListNode* next = cur;
ListNode* pre = dummyHead;
while(cur){//四个步骤
next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
//cout<<pre->val<<endl;
}
head = pre;
//cout<<head->val;
dummyHead->next->next = nullptr;
delete dummyHead;
return head;
}
};
- 两种递归写法(想不到用递归解法,但是思路很好,搬运过来方便复习)
//从前向后递归(卡哥的)
class Solution {
public:
ListNode* reverse(ListNode* pre,ListNode* cur){
if(cur == NULL) return pre;//递归结束条件
ListNode* temp = cur->next;
cur->next = pre;
return reverse(cur,temp);
}
ListNode* reverseList(ListNode* head) {
return reverse(NULL, head);
}
};
//从后向前(leetcode官方题解)
class Solution {
public:
ListNode* reverseList(ListNode* head) {
// 边缘条件判断
if(head == NULL) return NULL;
if (head->next == NULL) return head;
// 递归调用,翻转第二个节点开始往后的链表
ListNode *last = reverseList(head->next);
// 翻转头节点与第二个节点的指向
head->next->next = head;
// 此时的 head 节点为尾节点,next 需要指向 NULL
head->next = NULL;
return last;
}
};