LeetCode203.移除链表元素
题目链接:LeetCode203.移除链表元素
本题思路:
- 链表数据结构对于增加删除元素效率很高,所以用指针来遍历要移除的元素
- 用两个指针,一个指向删除的节点,一个指向待删除节点之前的节点
c++代码
/**
* 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 && head->val == val){
ListNode *tmp = head;
head = head->next;
delete tmp;
}
// 删除非头节点
ListNode *cur = head;
while (cur && cur->next != nullptr){
if (cur->next->val == val){
ListNode *tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}else{
cur = cur->next;
}
}
return head;
}
};
虚拟头节点
/**
* 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 *dummyHead = new ListNode();
dummyHead->next = head;
ListNode *cur = dummyHead;
while (cur->next != nullptr) {
if (cur->next->val == val){
ListNode *tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}else{
cur = cur->next;
}
}
return dummyHead->next;
}
};
本题收获
- while必须写两个判断,处理两种情况,
[] val=1
结果为[]
,不加cur!= nullptr
会使cur->next
空指针异常;[1,2,2] val=2
末尾有待删除元素,不加cur->next != nullptr
会使cur->next->val
空指针异常。 - 对于单链表,删除一个元素一定要知道上一个元素是什么。
- 采用虚拟头节点是头节点和非头结点操作统一
LeetCode707.设计链表
题目链接:LeetCode707.设计链表
遇到的问题:
- 主要问题是空指针异常问题较多
- 判断特殊情况
C++代码
class MyLinkedList {
public:
MyLinkedList() {
size = 0;
dummyHead = new ListNode(0);
}
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){}
};
int get(int index) {
if ( index < 0 || index > (size -1)) return -1;
ListNode *p = dummyHead->next;
while(index --) {
p = p->next;
}
return p->val;
}
void addAtHead(int val) {
ListNode *node = new ListNode(val);
ListNode *p = dummyHead;
node->next = p->next;
p->next = node;
size ++;
}
void addAtTail(int val) {
ListNode *p = dummyHead;
while(p->next != nullptr){
p = p->next;
}
ListNode *node = new ListNode(val);
p->next = node;
size++;
}
// 在第index个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
// 如果index 等于链表的长度,则说明是新插入的节点为链表的尾结点
// 如果index大于链表的长度,则返回空
// 如果index小于0,则在头部插入节点
void addAtIndex(int index, int val) {
if (index < 0) index = 0;
if (index > size) return;
ListNode *node = new ListNode(val);
ListNode *p = dummyHead;
while( index --) {
p = p->next;
}
node->next = p->next;
p->next = node;
size++;
}
void deleteAtIndex(int index) {
if (index < 0 || index > (size - 1)) return;
ListNode *p = dummyHead;
while(index--) {
p = p->next;
}
ListNode *tmp = p->next;
p->next = p->next->next;
delete tmp;
tmp = nullptr;
size--;
}
private:
int size;
ListNode *dummyHead;
};
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList* obj = new MyLinkedList();
* int param_1 = obj->get(index);
* obj->addAtHead(val);
* obj->addAtTail(val);
* obj->addAtIndex(index,val);
* obj->deleteAtIndex(index);
*/
本题收获
- 本题综合性很强,我觉得即要求对c++类、结构体的知识理解,还要对链表各种遍历和增删改查深入研究,以及对各种特殊情况的处理。
LeetCode206.反转链表
题目链接:LeetCode206.反转链表
本题思路:
- 一开始想到了栈的数据结构,但似乎加大了本题难度
- 之后还是没有想出解决办法
C++代码
双指针法
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;
}
};
根据双指针法,递归法也不难写出
递归法
/**
* 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 *reverse(ListNode *pre, ListNode *cur){
if (cur == nullptr) return pre;
ListNode *tmp = cur->next;
cur->next = pre;
return reverse(cur, tmp);
}
ListNode* reverseList(ListNode* head) {
return reverse(nullptr, head);
}
};
本题收获
- 原来可以改变
next
指向来改变链表方向,最后返回pre
就能实现逆转链表。