算法随想Day3【链表】| LC203-移除链表元素、LC707-设计链表、LC206-反转链表
LC203. 移除链表元素
本题最关键是要理解虚拟头结点的使用技巧,这个对链表题目很重要。
自己在做时,定义了一个虚拟头节点,然后又分别定义了ptr和prev指向迭代中当前的节点和上一个节点,定义的变量有点多,但是这种思路更容易想出且更方便个人理解。
/**
* 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 virtual_head; //虚拟头节点
virtual_head.next = head;
ListNode* prev = &virtual_head;
ListNode* ptr = head;
ListNode* DeleteNode;
if (nullptr == head)
{
return head;
}
while (ptr != nullptr)
{
if (val == ptr->val)
{
prev->next = ptr->next;
DeleteNode = ptr;
ptr = ptr->next;
delete DeleteNode;
}
else
{
prev = ptr;
ptr = ptr->next;
}
}
return virtual_head.next;
}
};
官方解法就省去了prev和ptr这些定义,更加简洁
ListNode* removeElements(ListNode* head, int val)
{
struct ListNode* dummyHead = new ListNode(0, head);
struct ListNode* temp = dummyHead;
while (temp->next != NULL) {
if (temp->next->val == val) {
temp->next = temp->next->next;
} else {
temp = temp->next;
}
}
return dummyHead->next;
}
递归思路
ListNode* removeElements(ListNode* head, int val) {
if (head == nullptr) {
return head;
}
head->next = removeElements(head->next, val);
return head->val == val ? head->next : head;
}
LC707. 设计链表
之前写得比较多,比较顺利写出来了,顺便写个demo验证下
#include <iostream>
using namespace std;
struct ListNode
{
int val;
ListNode* prev;
ListNode* next;
ListNode() : val(0), next(nullptr) {}
ListNode(int val) : val(val), prev(nullptr), next(nullptr) {};
ListNode(int val, ListNode* prev, ListNode* next) : val(val), prev(prev), next(next) {};
};
class MyLinkedList
{
public:
ListNode* head;
ListNode* tail;
MyLinkedList()
{
this->head = new ListNode(0);
this->tail = new ListNode(0);
head->prev = nullptr;
tail->next = nullptr;
head->next = tail;
tail->prev = head;
}
int get(int index)
{
ListNode* ptr = head->next;
while (index-- && ptr != nullptr && ptr->next != nullptr)
{
ptr = ptr->next;
}
return ptr == nullptr ? -1 : ptr->val;
}
void addAtHead(int val)
{
ListNode* ptr = new ListNode(val);
head->next->prev = ptr;
ptr->next = head->next;
ptr->prev = head;
head->next = ptr;
}
void addAtTail(int val)
{
ListNode* ptr = new ListNode(val);
tail->prev->next = ptr;
ptr->prev = tail->prev;
ptr->next = tail;
head->prev = ptr;
}
void addAtIndex(int index, int val)
{
if (index < 0)
{
addAtHead(val);
}
ListNode* newNode = new ListNode(val);
ListNode* ptr = head;
while (index-- && ptr != nullptr && ptr->next != nullptr)
{
ptr = ptr->next;
}
if (nullptr == ptr->next)
{
return;
}
else
{
ptr->next->prev = newNode;
newNode->next = ptr->next;
newNode->prev = ptr;
ptr->next = newNode;
}
}
void deleteAtIndex(int index)
{
ListNode* ptr = head->next;
while (index-- && ptr != nullptr && ptr->next != nullptr)
{
ptr = ptr->next;
}
if (nullptr == ptr->next )
{
return;
}
else
{
ptr->next->prev = ptr->prev;
ptr->prev->next = ptr->next;
delete ptr;
}
}
};
int main()
{
MyLinkedList* linkedList = new MyLinkedList();
linkedList->addAtHead(1);
linkedList->addAtIndex(-3, 4);
linkedList->addAtTail(3);
linkedList->addAtIndex(1, 2);
linkedList->addAtIndex(4, 2); //链表变为4-> 2-> 1-> 3
int a = 0;
a = linkedList->get(1); //返回2
cout << a << endl;
linkedList->deleteAtIndex(1); //现在链表是4-> 1-> 3
linkedList->deleteAtIndex(4); //无效操作
a = linkedList->get(1); //返回1
cout << a << endl;
}
LC206. 反转链表
之前做过,但是思路又没有了,终究是当时没有理解的透彻,而且对这类单链表的题目没有总结和思考,今天补充下,加强印象,多刷题提高。
ListNode* reverseList(ListNode* head)
{
ListNode* curr = head;
ListNode* prev = nullptr;
ListNode* temp = nullptr;
while (curr != nullptr)
{
////先保存curr的next,以免改变指针指向后找不到next了
temp = curr->next;
curr->next = prev;
prev = curr;
curr = temp;
}
return curr;
}
思考:
在单链表中操作某个节点时:
1、一般要有两个指针,分别记录或表示该节点前面和后面的两个节点的状态(包括头节点head,创建一个虚拟节点virtual_head置于它的前面)。
2、若需要遍历链表,一般情况下,创建一个current指针,对一条链表从头到尾做一次遍历即可,开始时判断下是使curr指向head还是virtual_head。
- 对“LC203. 移除链表元素”这道题,创建一个virtual_head作为其虚拟头节点。curr从virtual_head开始遍历,需要移除某个匹配元素(curr->next)时,只需使curr->next = curr->next=>next即可
- 对“LC206. 反转链表”这道题,curr从链表第一个开始遍历即可,创建一个prev记录curr的前向节点指针(对于该题目,prev应该初始化为nullptr),同时还要定义一个后向指针暂时存储curr->next
递归思路:
为什么可以使用递归:

递归接替思路:

ListNode* reverseList(ListNode* head) {
if (head == nullptr || head->next == nullptr) return head;
ListNode* p = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return p;
}

浙公网安备 33010602011771号