代码随想录训练营第三天|203.移除链表元素 ;707.设计链表 ;206.反转链表
[203-题目链接](203. 移除链表元素 - 力扣(LeetCode))
解题状态:已通过
我的解答:
class Solution {
public:
ListNode* removeElements(ListNode* head, int val)
{
struct ListNode h_node;
h_node.next = head;
h_node.val = 0;
ListNode* after = head;
ListNode* front = &h_node;
while(after!=nullptr)
{
if(after->val==val)
{
front->next = after->next;
after = after->next;
}
else
{
after = after->next;
front = front->next;
}
}
return h_node.next;
}
};
解题思路:首先为链表增加一个虚拟的头节点(为了统一列表元素的操作方式,如果不增加,删除链表中间节点的操作与删除第一个节点操作会不一致),设置前后指针,【前指针front】指向虚拟头节点,【后指针after】指向链表的第一个节点,当链表为空时,直接返回虚拟头节点的下一节点,即真正的头节点。当链表不为空时,检查after指向的当前节点值val是否为需要删除的值,如果需要删除,首先将前指针的next属性指向ater的next,即删除操作,然后将ater移动到next,继续搜索需要删除的节点。如果当前节点不是需要删除的节点,则front和after一起向后遍历,当after为nullptr时,对整个链表的操作结束。
代码随想录题解:
【无虚拟头节点】
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
// 删除头结点
while (head != NULL && head->val == val) { // 注意这里不是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;
}
};
解题思路:当不使用虚拟头节点的时候,头节点和非头节点就需要分开处理,第一个while循环对头节点进行处理,当跳出循环时,头节点就不可能是需要删除的节点,接下来的非头节点就是按照【遍历->检查->删除(移到下一节点)】的步骤进行。
【虚拟头节点】
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;
}
};
解题思路:和我的解法基本一致,但这个写法更规范,因为他还进行了delete释放已经删除节点的内存
[题目解析](代码随想录 (programmercarl.com))
[视频讲解](手把手带你学会操作链表 | LeetCode:203.移除链表元素_哔哩哔哩_bilibili)
[707-题目链接](707. 设计链表 - 力扣(LeetCode))
解题状态:已通过
我的解答:
class MyLinkedList
{
public:
struct ListNode
{
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
};
MyLinkedList()
{
head = new ListNode;
head->val = 0;
head->next = nullptr;
size = 0;
}
int get(int index)
{
if(index<0 || index>size-1)
{
return -1;
}
ListNode* ptr;
ptr = head->next;
if(ptr==nullptr && index>0)
{
return -1;
}
int pos=0;
while(true)
{
if(pos==index)
{
return ptr->val;
}
ptr = ptr->next;
pos++;
}
}
void addAtHead(int val)
{
ListNode* new_node = new ListNode;
new_node->val = val;
new_node->next = head->next;
head->next = new_node;
size++;
}
void addAtTail(int val)
{
if(size==0)
{
ListNode* new_node = new ListNode;
new_node->val = val;
new_node->next = nullptr;
head->next = new_node;
size++;
}
else
{
ListNode* ptr = head->next;
while(ptr->next!=nullptr)
{
ptr = ptr->next;
}
ListNode* new_node = new ListNode;
new_node->val = val;
new_node->next = nullptr;
ptr->next = new_node;
size++;
}
}
void addAtIndex(int index, int val)
{
if(index>size)
{
return;
}
else if(index==size && size!=0)
{
ListNode* ptr = head->next;
while(ptr->next!=nullptr)
{
ptr = ptr->next;
}
ListNode* new_node = new ListNode;
new_node->val = val;
new_node->next = nullptr;
ptr->next = new_node;
size++;
return;
}
else
{
if(index==0)
{
ListNode* new_node = new ListNode;
new_node->val = val;
new_node->next = head->next;
head->next = new_node;
size++;
return;
}
else
{
int pos = 0;
ListNode* ptr = head->next;
ListNode* front = head;
while(pos!=index)
{
ptr = ptr->next;
front = front->next;
pos++;
}
ListNode* new_node = new ListNode;
new_node->val = val;
new_node->next = ptr;
front->next = new_node;
size++;
return;
}
}
}
void deleteAtIndex(int index)
{
if(index<0 || index>size-1)
{
return;
}
int pos = 0;
ListNode* ptr = head->next;
ListNode* front = head;
while(pos!=index)
{
pos++;
ptr = ptr->next;
front = front->next;
}
front->next = ptr->next;
size--;
return;
}
private:
ListNode* head;
int size;
};
解题思路:这题就是练习基本的链表【增删查】,不涉及算法,就不细说了,感兴趣的可以看一下代码随想录的文章和视频。
[题目解析](707. 设计链表 - 力扣(LeetCode))
[206-题目链接](206. 反转链表 - 力扣(LeetCode))
解题状态:已通过
我的解答:
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==nullptr)
{
return head;
}
ListNode *new_head = new ListNode;
new_head->val = 0;
ListNode* ptr = head;
ListNode* temp = nullptr;
while(ptr!=nullptr)
{
temp = ptr;
ptr = ptr->next;
temp->next = new_head->next;
new_head->next = temp;
}
return new_head->next;
}
};
解题思路:我的方法是采用【头插法】创建一个反转链表,从原始的链表中的头节点开始,把节点不断取下来,再不断地插入到新链表里,每一次插入都插在第一个节点之前,这样在插入操作结束时,就构成了一个反转链表。在具体实现上,因为需要插入进新链表的节点我们需要修改它的next属性,但我们还需要不断遍历剩下的待插入的节点,所以就使用了一个新的指针temp指向当前需要执行插入的节点,让之前指向该节点的ptr指针向后移,遍历后面待插入的节点。
代码随想录题解:双指针法
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* temp; // 保存cur的下一个节点
ListNode* cur = head;
ListNode* pre = NULL;
while(cur) {
temp = cur->next; // 保存一下 cur的下一个节点,因为接下来要改变cur->next
cur->next = pre; // 翻转操作
// 更新pre 和 cur指针
pre = cur;
cur = temp;
}
return pre;
}
};
代码随想录提供了三种解法,这是我感觉最好的一种,直接从到尾进行遍历,在每个节点都把next的指向更改向前指,在不构造
新链表的情况下,完成了链表逆转,包括这一种解法在内的三种解法,可以参考如下的讲解链接和视频。
[题目解析](代码随想录 (programmercarl.com))
[视频解析](帮你拿下反转链表 | LeetCode:206.反转链表 | 双指针法 | 递归法_哔哩哔哩_bilibili)