注意,链表中的结点一定要先判断是否为空! 且c++需要将删除的结点释放:
delete(temp);
第一题-203.移除链表元素
解答
删除链表中的元素与删除数组中的元素不同的是不需要后面元素的覆盖,只需要移动指针指向的位置即可,分为两种情况:
- 删除的是第一个结点:将头指针移动到后面的一个结点
- 删除的不是第一个结点:将删除结点的前一个结点指向后一个结点,释放删除节点的内存
这里提供一种统一以上两种情况的方式:虚拟头结点,即设计一个虚拟的头结点,让所有的结点都使用第二种情况删除
方法一:分类
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
//删除的是头结点
//注意此处使用循环(前几个都需要被删除)
while(head!=NULL&&head->val == val) {
ListNode *delet;
delet= head;//需要被释放
head = head->next;
//释放原来的头结点
delete delet;
}
//删除的不是头结点
ListNode *current=head;//最后返回head,避免被更改
//此时current->next需要被删除,因此需要判空
while (current != NULL&& current->next != NULL) {
if (current->next->val == val) {
ListNode *delet;//需要被释放
delet = current->next;//需要被释放
current->next = current->next->next;
delete delet;
}
else {
current = current->next;
}
}
return head;
}
};
方法二:虚拟头结点
leetcode出现报错:
解决方法:
将ListNode* virhead=new ListNode(0)初始化
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* virhead=new ListNode(0);
virhead->next= head;//设置虚拟头结点
ListNode* current = virhead;
while (current != NULL && current->next != NULL) {
if (current->next->val == val) {
ListNode* delet = current->next;
current->next = current->next->next;
delete delet;
}
else {
current = current->next;
}
}
head = virhead->next;
delete virhead;
return head;
}
};
第二题-707.设计链表
本题考验的是基础的链表解决能力,比较花费时间,但不算太难,主要是要注意初始化和插入位置是否符合规定
class MyLinkedList {
public:
struct ListNode {
int val;
ListNode* next;
ListNode(int val):val(val),next(nullptr){}
};
MyLinkedList() {
virhead = new ListNode(0);
size = 0;
}
int get(int index) {
ListNode* current;
current = virhead;
if (index<0 || index>(size - 1)) {
return -1;
}
for (int i = 0; i <= index; i++) {
current = current->next;
}
return current->val;
}
void addAtHead(int val) {
ListNode* add = new ListNode(val);
add->next = virhead->next;
virhead->next = add;
size++;
}
void addAtTail(int val) {
ListNode* current;
current = virhead;
while (current->next != NULL) {
current = current->next;
}
ListNode* add=new ListNode(val);
current->next = add;
add->next = NULL;
size++;
}
void addAtIndex(int index, int val) {
if(index>size)return;
ListNode* current;
current = virhead;
for (int i = 0; i <index; i++) {
if (current == NULL) {
return;
}
current = current->next;
}
ListNode* add = new ListNode(val);
add->next = current->next;
current->next = add;
size++;
}
void deleteAtIndex(int index) {
if (index<0 || index>(size - 1)) {
return;
}
ListNode* current;
current = virhead;
for (int i = 0; i < index; i++) {
current = current->next;
}
ListNode* dele;
dele = current->next;
current->next = current->next->next;
delete(dele);
size--;
}
private:
int size;
ListNode* virhead;
};
第三题-206.反转链表
方法一:双指针法
主要思想是改变指针指向的方向,定义两个指针,遍历整个链表,改变指针指向即可
/**
* 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* reverseList(ListNode* head) {
ListNode* current=head;
//pre指向前面
ListNode* pre = NULL;
while (current != NULL) {
ListNode* temp;
//存放下一个结点
temp = current->next;
//改变指针方向
current->next = pre;
pre = current;
current = temp;
}
return pre;
}
};
方法二:递归
递归和双指针法类似,关键在于递归结束的条件
class Solution {
public:
ListNode* reverseList(ListNode* head) {
//调用反转函数
return reverse(NULL, head);
}
ListNode* reverse(ListNode* pre,ListNode* current) {
if (current == NULL) {
return pre;
}
ListNode* temp;
temp = current->next;
current->next = pre;
return reverse(current, temp);
}
};