持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情
1、写在前面
大家好,我是翼同学,这里是【水滴计划 | 刷题日志】
每日两题,拒绝摆烂。
2、内容
2.1、题目一:移除链表元素
(1) 描述
(2) 举例
(3) 解题
如果头结点的值刚好是目标元素的话,则需要删除该结点。但由于头结点的删除操作和普通结点的删除操作并不同。为什么不同?因为其他结点有前驱元素和后继元素,但头结点只有后继元素,也就是说在头结点之前是没有元素的。
因此为了方便运算,也能使代码得到统一,我们可以定义一个虚拟头结点。
示意图如下:
代码如下:
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
// 设置一个头结点
ListNode* p = new ListNode(0);
// 头结点指向head,方便后续运算
p->next = head;
// 定义一个工作指针 cur
ListNode* cur = p;
// 利用工作指针来循环遍历链表
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
head = p->next;
// 删除工作指针
delete p;
// 返回结果
return head;
}
};
当然,如果不想设一个虚拟头结点,那就得先对头结点进行判断处理,再对其他结点进行判断处理。
代码如下:
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
// 对头结点的情况进行判断并处理
while (head != NULL && head->val == val) {
// 将头结点向后移动即可移除该头结点(记得释放掉头结点)
ListNode* p = head;
head = head->next;
delete p;
}
// 对其他结点进行判断并处理
ListNode* cur = head;
while (cur != NULL && cur->next!= NULL) {
if (cur->next->val == val) {
ListNode* p = cur->next;
cur->next = cur->next->next;
delete p;
}
else {
cur = cur->next;
}
}
return head;
}
};
2.2、题目二:设计链表
(1) 描述
(2) 举例
(3) 解题
同样的,这里我们也定义一个虚拟头结点。
class MyLinkedList {
private:
int size; // 长度
LinkNode* pHead; // 虚拟头结点
public:
// 首先写一个结构体来定义链表的结点
struct LinkNode {
int val;
LinkNode* next;
LinkNode(int val):val(val), next(NULL) { }
};
// 构造函数
MyLinkedList() {
pHead = new LinkNode(0);
size = 0;
}
// 取第 index 个结点的值
int get(int index) {
// 检查 index 取值范围
if (index < 0 || index > (size - 1)) {
return -1;
}
// 定义一个工作指针 cur,指向虚拟头结点的下一个结点(即首结点)
LinkNode* cur = pHead->next;
// 寻找目标结点
while(index--) {
cur = cur->next;
}
// 返回当前结点的值
return cur->val;
}
// 添加一个结点,并且该结点是链表新的头结点
void addAtHead(int val) {
// 创建一个值为 val 的新结点 newNode
LinkNode* newNode = new LinkNode(val);
// 将首结点定义为新结点的下一位结点
newNode->next = pHead->next;
// 将新结点定义为首结点
pHead->next = newNode;
// 长度记得加一
size++;
}
// 在链表的尾部添加新的结点
void addAtTail(int val) {
// 创建一个值为 val 的新结点 newNode
LinkNode* newNode = new LinkNode(val);
// 创建一个工作指针 cur
LinkNode* cur = pHead;
// 遍历链表,最后工作指针指向了链表的尾部
while(cur->next != NULL){
cur = cur->next;
}
// 添加新的结点
cur->next = newNode;
// 长度记得加一
size++;
}
// 在链表中的第 index 个节点之前添加值为 val 的节点。
void addAtIndex(int index, int val) {
// 检查插入位置范围的合法性
if (index < 0 || index > size) {
return -1;
}
// 创建一个值为 val 的新结点 newNode
LinkNode* newNode = new LinkNode(val);
// 创建一个工作指针 cur
LinkNode* cur = pHead;
// 遍历链表,找到指定位置
while(index--) {
cur = cur->next;
}
// 将新结点的下一位结点指向了原先结点的下一位
newNode->next = cur->next;
// 将新结点定义为原结点的下一位结点
cur->next = newNode;
// 记得长度加一
size++;
}
// 删除链表中的第 index 个节点
void deleteAtIndex(int index) {
// 检查插入位置范围的合法性
if (index < 0 || index >= size) {
return -1;
}
// 创建一个工作指针 cur
LinkNode* cur = pHead;
// 遍历链表,找到指定位置
while(index--) {
cur = cur ->next;
}
// 删除操作
LinkNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
size--;
}
};
3、写在最后
好了,今天就刷到这里,明天再来。