代码随想录算法训练营第三天 |203.移除链表元素、 707.设计链表、 206.反转链表
文章讲解:代码随想录
链表节点的定义:
// 单链表
struct ListNode {
int val; // 节点上存储的元素
ListNode *next; // 指向下一个节点的指针
ListNode(int x) : val(x), next(NULL) {} // 节点的构造函数
};
1. 移除链表元素
思路:判断要删除的是否是头节点或者非头节点,之后根据不同类型进行判断,最后注意释放内存。
新思路:设置虚拟头节点
第一种思路(原链表删除元素)
/**
* 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)
{
while(head != NULL && head->val == val)//注意不能用if,因为if为单次判断,可能会漏掉其余要删除的元素
{
ListNode *tmp = head;
head = head ->next;
delete tmp;
}
ListNode *cur = head;//定义的临时的指针
while( cur != NULL && cur->next!= NULL)
{
if(cur->next->val == val)
{
ListNode *tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}else
{
cur = cur->next;
}
}
return head;
}
};
第二种思路(使用虚拟头节点)
利用虚拟头节点来合并两种类型,统一去判断,更简洁
class Solution {
public:
ListNode* removeElements(ListNode* head, int val)
{
ListNode *dummyHead = new ListNode(0);
dummyHead->next = 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;
}
};
注:
- 遍历链表不能直接用头节点遍历,因为头节点所指向的值是不断变化的(无法返回原先列表的头节点),所以有一个临时的cur指针来遍历链表。
- 此处不能直接返回原先的head,因为之前的head可能已经被删掉。
head = dummyHead->next;
delete dummyHead;
return head;
2、设计链表
思路:直接虚拟头节点!
1、删除节点;第N个节点一定是cur->next 这样才能操作cur来指向新节点,才能删掉第N个
2、使用 while(index–) 是正确的,因为它允许循环从 index 的原始值开始迭代,直到 index 变为 -1
//赋值顺序易错
newNode->next = dummyhead->next;
dummyhead->next = newNode;
3、当前遍历节点一定要指向尾部节点,这样才能让尾部节点指向newnode
4、从哑节点开始遍历是因为你想要找到链表的最后一个节点,并将新节点添加到其后。哑节点作为链表的起点,提供了一种统一和简洁的方式来处理链表操作,特别是当涉及到链表的头部和尾部时。
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 >(size - 1)||index < 0)
{
return -1;
}
LinkedNode *cur = dummyhead->next;
while(index--)
{
cur = cur->next;
}
return cur->val;
}
void addAtHead(int val)
{
LinkedNode *newNode = new LinkedNode(val);
newNode->next =dummyhead->next;
dummyhead->next = newNode;
size++;
}
void addAtTail(int val)
{
LinkedNode *newNode = new LinkedNode(val);
LinkedNode *cur = dummyhead;
while(cur->next !=nullptr)
{
cur = cur->next;
}
cur->next = newNode;
size++;
}
void addAtIndex(int index, int val)
{
if(index > size) return;
if(index < 0) index = 0;
LinkedNode *newNode = new LinkedNode(val);
LinkedNode *cur = dummyhead;
while(index--) {
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
size++;
}
void deleteAtIndex(int index)
{
if(index >= size || index < 0)
{
return;
}
LinkedNode *cur=dummyhead;
while(index--)
{
cur = cur->next;
}
LinkedNode *tmp = cur->next;
cur->next=cur->next->next;
delete tmp;
tmp=nullptr;
size--;
}
void printLinkedList() {
LinkedNode *cur = dummyhead;
while (cur->next != nullptr) {
cout << cur->next->val << " ";
cur = cur->next;
}
cout << endl;
}
private:
int size;
LinkedNode *dummyhead;
};
3、反转链表
1、思路:双指针
class Solution {
public:
ListNode* reverseList(ListNode* head)
{
ListNode *cur = head;
ListNode *tmp;
ListNode *pre = NULL;
while(cur)
{
tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
};
pre = cur;
cur = tmp;
此处的顺序要注意
2、递归法
头节点返回给reverse函数 函数再返回给主函数(reverseList)
脑子懂了,手说不会