代码随想录算法训练营第三天|LeetCode203.移除链表元素 LeetCode707.设计链表 LeetCode206.反转链表

代码随想录算法训练营

代码随想录算法训练营第三天|LeetCode203.移除链表元素 LeetCode707.设计链表 LeetCode206.反转链表



前言

今天是链表的第一天,主要练习链表的基本操作,内存操作,以及虚拟头结点的方法
(期末时间紧张,博客是后来补上的,o(╥﹏╥)o
参考文章:
LeetCode203.移除链表元素
LeetCode707.设计链表
LeetCode206.反转链表


一、LeetCode203.移除链表元素

1、题目链接

LeetCode203.移除链表元素

2、思路

(1)遍历链表的方式:
设两个指针pre和p,分别代表上一个节点和当前节点,初始pre指向虚拟头结点dummy,p指向头结点head
(2)如何删除节点:
pre->next = p->next;
删除后移动p: p = p->next;
(3)不删除节点时更新:pre和p都向后移动
pre = pre->next;
p = p->next;
(4)对删除头结点的特殊处置:
ListNode* tmp = head;
head = head->next;
由于最后返回head,所以要改变head,而我们之前删除节点的方法没有改变head

3、细节

(1)为什么删除头结点用while进行判断:
头结点可能连着多个值为val的节点,
在进入主循环前处理掉所有头结点删除的情况
(2)定义dummy虚拟头结点,要初始化,否则dummy为空指针,不能使用dummy->next
(3)new创建对象:
new与malloc不同,new可以指定分配到内存空间对应的变量类型,并在分配内存的同时对指针所指变量进行赋值。
new与delete配合使用
new常用用法:new 构造函数()

4、题解

/**
 * 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* dummy = new ListNode(0, head);

        ListNode* p;
        ListNode* pre;
        p = head;
        pre = dummy;
        while (head != NULL && head->val == val) {
            ListNode* tmp = head;
            head = head->next;
        }
        while (p != NULL) {
            if (p->val == val) {

                pre->next = p->next;
                p = p->next;
            } else {
                pre = pre->next;
                p = p->next;
            }
        }
        return head;
    }
};

二、LeetCode707.设计链表

1.题目链接

LeetCode707.设计链表

2.思路

(1)使用虚拟头结点dummy,作为指针遍历的起点
(2)用链表长度辅助遍历---->注意:一定要确保每次增删节点size都能正确更新

3.题解

class MyLinkedList {
public:
    struct listnode {
        int val;
        listnode* next;

        listnode(int x) : val(x), next(NULL){};
    };
    listnode* dummy;
    int size;
    MyLinkedList() { // 初始化
        dummy = new listnode(0);
        size = 0;
    }

    int get(int index) {
        if (index > size - 1 || index < 0)
            return -1;
        listnode* p = dummy->next;
        for (int i = 0; i < index; i++) {
            p = p->next;
        }
        return p->val;
    }

    void addAtHead(int val) {
        listnode* temp = new listnode(val);
        if (dummy->next == NULL)
            dummy->next = temp;
        else {
            temp->next = dummy->next;
            dummy->next = temp;
        }
        size++;
    }

    void addAtTail(int val) {

        listnode* temp = new listnode(val);
        if (dummy->next == NULL) {
            dummy->next = temp;
            size++;
            return;
        }
        listnode* p = dummy->next;
        for (int i = 0; i < size - 1; i++) {
            p = p->next;
        }
        p->next = temp;
        size++;
    }

    void addAtIndex(int index, int val) {
        if (index == 0)
            return addAtHead(val);
        if (index == size)
            return addAtTail(val);
        if (index > size)
            return;
        listnode* temp = new listnode(val);
        listnode* p = dummy;
        for (int i = 0; i < index; i++) {
            p = p->next;
        }
        temp->next = p->next;
        p->next = temp;
        size++;
    }

    void deleteAtIndex(int index) {
        if (index < 0 || index >= size)
            return;
        listnode* p = dummy;
        for (int i = 0; i < index; i++) {
            p = p->next;
        }
        p->next = p->next->next;
        size--;
    }
};

三、LeetCode206.反转链表


1、题目链接

LeetCode206.反转链表

2、思路

(1)翻转链表本质上是翻转每个节点的指针,让每个节点的next都指向原本在前面的那个节点,最终返回原来链表的最后一个节点
(2)需要两个指针遍历
cur表示当前正在被翻转的节点
pre是cur的上一个节点
(3)翻转操作:
temp保存cur的下一个节点 :pre->cur->temp
cur->next变为pre: pre-><-cur temp
cur和pre各自前进一步
(4)结束条件:cur为空,此时pre是原来链表的最后一个节点
(5)实现方法有两种:迭代和递归
1)迭代:利用循环
2)递归:
构造函数reverse_node,每次调用实现一个节点的翻转

3、题解

(1)迭代

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* cur = head;
        ListNode* pre = NULL;
        ListNode* temp;
        while (cur != NULL) {
            temp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }
};

(2)递归

class Solution {
public:
ListNode* reverse_node(ListNode* cur,ListNode* pre)
{
    if(cur==NULL)return pre;
    ListNode *temp=cur->next;
    cur->next=pre;
    pre=cur;
    return reverse_node(temp,pre);
}
ListNode* reverseList(ListNode* head) {
        ListNode* cur=head;
        ListNode* pre=NULL;
        return reverse_node(cur,pre) ;
    }
    
};

总结

对类和对象的复习:
构造函数
类名():成员名()…{};
例如:listnode(int x,listnode* n) val(x),next(n){};//构造函数
结构体进而类都可以定义构造函数,不过结构体成员默认public,类成员默认private

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值