【水滴计划 | 每日两题】:设计链表、移除链表元素

73 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情

1、写在前面

大家好,我是翼同学,这里是【水滴计划 | 刷题日志】

每日两题,拒绝摆烂。

2、内容

2.1、题目一:移除链表元素

链接:203. 移除链表元素 - 力扣(LeetCode)

(1) 描述

image.png

(2) 举例

image.png

image.png

image.png

image.png

(3) 解题

如果头结点的值刚好是目标元素的话,则需要删除该结点。但由于头结点的删除操作和普通结点的删除操作并不同。为什么不同?因为其他结点有前驱元素和后继元素,但头结点只有后继元素,也就是说在头结点之前是没有元素的。

因此为了方便运算,也能使代码得到统一,我们可以定义一个虚拟头结点。

示意图如下:

image.png

代码如下:

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;
    }
};

image.png


当然,如果不想设一个虚拟头结点,那就得先对头结点进行判断处理,再对其他结点进行判断处理。

代码如下:

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;
    }
};

image.png

2.2、题目二:设计链表

链接:707. 设计链表 - 力扣(LeetCode)

(1) 描述

image.png

(2) 举例

image.png

image.png

(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--;
    }
};

image.png


3、写在最后

好了,今天就刷到这里,明天再来。