代码随想录算法训练营
代码随想录算法训练营第三天|LeetCode203.移除链表元素 LeetCode707.设计链表 LeetCode206.反转链表
文章目录
前言
今天是链表的第一天,主要练习链表的基本操作,内存操作,以及虚拟头结点的方法
(期末时间紧张,博客是后来补上的,o(╥﹏╥)o
参考文章:
LeetCode203.移除链表元素
LeetCode707.设计链表
LeetCode206.反转链表
一、LeetCode203.移除链表元素
1、题目链接
2、思路
(1)遍历链表的方式:
设两个指针pre和p,分别代表上一个节点和当前节点,初始pre指向虚拟头结点dummy,p指向头结点head
(2)如何删除节点:
pre->next = p->next;
删除后移动p: p = p->next;
(3)不删除节点时更新:pre和p都向后移动
pre = pre->next;
p = p->next;
(4)对删除头结点的特殊处置:
ListNode* tmp = head;
head = head->next;
由于最后返回head,所以要改变head,而我们之前删除节点的方法没有改变head
3、细节
(1)为什么删除头结点用while进行判断:
头结点可能连着多个值为val的节点,
在进入主循环前处理掉所有头结点删除的情况
(2)定义dummy虚拟头结点,要初始化,否则dummy为空指针,不能使用dummy->next
(3)new创建对象:
new与malloc不同,new可以指定分配到内存空间对应的变量类型,并在分配内存的同时对指针所指变量进行赋值。
new与delete配合使用
new常用用法:new 构造函数()
4、题解
/**
* 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) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummy = new ListNode(0, head);
ListNode* p;
ListNode* pre;
p = head;
pre = dummy;
while (head != NULL && head->val == val) {
ListNode* tmp = head;
head = head->next;
}
while (p != NULL) {
if (p->val == val) {
pre->next = p->next;
p = p->next;
} else {
pre = pre->next;
p = p->next;
}
}
return head;
}
};
二、LeetCode707.设计链表
1.题目链接
2.思路
(1)使用虚拟头结点dummy,作为指针遍历的起点
(2)用链表长度辅助遍历---->注意:一定要确保每次增删节点size都能正确更新
3.题解
class MyLinkedList {
public:
struct listnode {
int val;
listnode* next;
listnode(int x) : val(x), next(NULL){};
};
listnode* dummy;
int size;
MyLinkedList() { // 初始化
dummy = new listnode(0);
size = 0;
}
int get(int index) {
if (index > size - 1 || index < 0)
return -1;
listnode* p = dummy->next;
for (int i = 0; i < index; i++) {
p = p->next;
}
return p->val;
}
void addAtHead(int val) {
listnode* temp = new listnode(val);
if (dummy->next == NULL)
dummy->next = temp;
else {
temp->next = dummy->next;
dummy->next = temp;
}
size++;
}
void addAtTail(int val) {
listnode* temp = new listnode(val);
if (dummy->next == NULL) {
dummy->next = temp;
size++;
return;
}
listnode* p = dummy->next;
for (int i = 0; i < size - 1; i++) {
p = p->next;
}
p->next = temp;
size++;
}
void addAtIndex(int index, int val) {
if (index == 0)
return addAtHead(val);
if (index == size)
return addAtTail(val);
if (index > size)
return;
listnode* temp = new listnode(val);
listnode* p = dummy;
for (int i = 0; i < index; i++) {
p = p->next;
}
temp->next = p->next;
p->next = temp;
size++;
}
void deleteAtIndex(int index) {
if (index < 0 || index >= size)
return;
listnode* p = dummy;
for (int i = 0; i < index; i++) {
p = p->next;
}
p->next = p->next->next;
size--;
}
};
三、LeetCode206.反转链表
1、题目链接
2、思路
(1)翻转链表本质上是翻转每个节点的指针,让每个节点的next都指向原本在前面的那个节点,最终返回原来链表的最后一个节点
(2)需要两个指针遍历
cur表示当前正在被翻转的节点
pre是cur的上一个节点
(3)翻转操作:
temp保存cur的下一个节点 :pre->cur->temp
cur->next变为pre: pre-><-cur temp
cur和pre各自前进一步
(4)结束条件:cur为空,此时pre是原来链表的最后一个节点
(5)实现方法有两种:迭代和递归
1)迭代:利用循环
2)递归:
构造函数reverse_node,每次调用实现一个节点的翻转
3、题解
(1)迭代
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* cur = head;
ListNode* pre = NULL;
ListNode* temp;
while (cur != NULL) {
temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
};
(2)递归
class Solution {
public:
ListNode* reverse_node(ListNode* cur,ListNode* pre)
{
if(cur==NULL)return pre;
ListNode *temp=cur->next;
cur->next=pre;
pre=cur;
return reverse_node(temp,pre);
}
ListNode* reverseList(ListNode* head) {
ListNode* cur=head;
ListNode* pre=NULL;
return reverse_node(cur,pre) ;
}
};
总结
对类和对象的复习:
构造函数
类名():成员名()…{};
例如:listnode(int x,listnode* n) val(x),next(n){};//构造函数
结构体进而类都可以定义构造函数,不过结构体成员默认public,类成员默认private
280

被折叠的 条评论
为什么被折叠?



