第三天|203.移除链表元素 707.设计链表 206.反转链表
第三天|203.移除链表元素 707.设计链表 206.反转链表
203.移除链表元素
手把手带你学会操作链表 | LeetCode:203.移除链表元素_哔哩哔哩_bilibili
笔记
如果没有虚拟头节点,删除操作要分情况,分为头节点和非头节点。
使用虚拟头节点的方法能够让删除/添加操作统一化。
c++需要从内存中释放那个被删除的结点。
使用cur遍历的时候,我们删除的对象一定是cur->next ,因为我们需要删除那个结点的前一个结点地址
返回的时候应该是dummyHead->next ,因为可能头节点已经被删除掉了。
实操出现问题:
new 和delete
注意ListNode* dummyHead = new ListNode(0) ,要新开辟内存。
代码/对比
我自己的:
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyhead=new ListNode(0);//虚拟头节点
dummyhead->next=head;
auto cur=dummyhead;//从虚拟头节点的下一个结点(原本链表的头节点)开始遍历,也就是说,当前遍历的那个节点是cur->next而不是cur
while(cur->next!=nullptr)//循环条件:处理的那个结点非空
{
if(cur->next->val==val)
{
cur->next=cur->next->next;
}
else
cur=cur->next;
}
return dummyhead->next;
}
};
其他:
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
dummyHead->next = head; // 将虚拟头结点指向head,这样方便后面做删除操作
ListNode* cur = dummyHead;
while (cur->next != NULL) {
if(cur->next->val == val) {
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
} else {
cur = cur->next;
}
}
head = dummyHead->next;
delete dummyHead;
return head;
}
};
注意删除不必要的节点和虚拟头节点
707.设计链表
帮你把链表操作学个通透!LeetCode:707.设计链表_哔哩哔哩_bilibili
笔记
注意index 的起始位置。
添加node的时候注意先后顺序。
实操出现的问题
循环中修改了_size的大小,注意不要修改类似敏感参数。
代码/对比
我自己的:
class MyLinkedList {
public:
struct LinkedNode {
int val;
LinkedNode* next;
LinkedNode(int val):val(val), next(nullptr){}
};
MyLinkedList() {
_dummyHead = new LinkedNode(0); // 这里定义的头结点 是一个虚拟头结点,而不是真正的链表头结点
_size = 0;
}
int get(int index) {
if(index<0||index>(_size-1))//如果index无效
{
return -1;
}
LinkedNode* cur=_dummyHead;//cur->next表示当前遍历的值
while(index--)
{
cur=cur->next;
}
return cur->next->val;
}
void addAtHead(int val) {
LinkedNode* node=new LinkedNode(0);//创建一个新的节点
node->val=val;
node->next=_dummyHead->next;
_dummyHead->next=node;
_size++;//注意要自增
}
void addAtTail(int val) {
//先找到最后一个节点
LinkedNode* cur=_dummyHead;
while(cur->next!=nullptr)
{
cur=cur->next;
}//此时cur指向最后一个节点
//再添加节点
LinkedNode* node=new LinkedNode(0);
node->next=nullptr;
node->val=val;
cur->next=node;
_size++;
}
void addAtIndex(int index, int val) {
if(index>_size)//如果index无效
{
return;
}
if(index==_size)//如果等于长度,则调用addAtTtail
{
addAtTail(val);
return;
}
if(index<0)//如果小于0则在开头加;
{
index=0;
}
//找到index
LinkedNode* cur=_dummyHead;//cur->next表示当前遍历的值
while(index--)
{
cur=cur->next;
}
//插入新的节点
LinkedNode* node=new LinkedNode(0);
node->val=val;
node->next=cur->next;
cur->next=node;
//size自增
_size++;
}
void deleteAtIndex(int index) {
if(index<0||index>_size-1)//如果index无效
{
return;
}
//找到index
LinkedNode* cur=_dummyHead;//cur->next是当前遍历的值
while(index--)
{
cur=cur->next;
}
//删除cur->next
LinkedNode* temp=cur->next;
cur->next=cur->next->next;
delete temp;
temp=nullptr;
//size自减
_size--;
}
private:
int _size;
LinkedNode* _dummyHead;
};
206.反转链表
帮你拿下反转链表 | LeetCode:206.反转链表 | 双指针法 | 递归法_哔哩哔哩_bilibili
笔记
双指针法:
一个pre一个cur指针,遍历完全整个链表,对逐个指针翻转指向即可。
注意循环条件为while(cur)而不是while(pre),因为最后需要一个头指针,最后返回的pre就是那个头指针。
递归法:
递归复习:
递归的基本思想是某个函数直接或者间接地调用自身,这样原问题的求解就转换为了许多性质相同但是规模更小的子问题。求解时只需要关注如何把原问题划分成符合条件的子问题,而不需要过分关注这个子问题是如何被解决的。
递归的三个注意点:
1.函数要干什么?
2.递归的停止条件?
3.怎么把大问题转换为小问题?
对于这个问题:
1.函数是为了反转链表,大体逻辑和上边的双指针方法相同;
2.递归的停止条件是while(cur)
3.怎么把大问题转换为小问题:cur指针和pre指针往前移动。
实操出现问题
双指针法:一定要注意循环条件
代码/对比
双指针:
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre=nullptr;
ListNode* cur=head;
while(cur)//直到pre指针为空,停止
{
ListNode* temp=cur->next;
cur->next=pre;
pre=cur;
cur=temp;
}
return pre;
}
};
递归:
我自己的:
class Solution {
public:
ListNode* reverse(ListNode* pre, ListNode* cur){
//停止条件:
if(cur==nullptr)
{
return pre;
}
else//怎么把大问题转换为小问题:方向反转、pre和cur指针后移
{
ListNode* tmp=cur->next;
cur->next=pre;
pre=cur;
cur=tmp;
return reverse(pre,cur);
}
}
ListNode* reverseList(ListNode* head) {
return reverse(nullptr,head);
}
};
随想录上面的:
class Solution {
public:
ListNode* reverse(ListNode* pre,ListNode* cur){
if(cur == NULL) return pre;
ListNode* temp = cur->next;
cur->next = pre;
// 可以和双指针法的代码进行对比,如下递归的写法,其实就是做了这两步
// pre = cur;
// cur = temp;
return reverse(cur,temp);
}
ListNode* reverseList(ListNode* head) {
// 和双指针法初始化是一样的逻辑
// ListNode* cur = head;
// ListNode* pre = NULL;
return reverse(NULL, head);
}
};
注意return那块可以直接用cur和tmp;

浙公网安备 33010602011771号