【链表1】203.移除链表元素 707.设计链表 206.反转链表

文章讲述了在LeetCode题目中遇到的链表操作难题,包括移除特定值的元素、设计链表并实现get、add、delete等方法,重点介绍了虚拟头节点的概念以及处理链表时需要注意的索引变化问题。
摘要由CSDN通过智能技术生成

203.移除链表元素

链接

(1)文字讲解:https://programmercarl.com/0203.移除链表元素.html#思路
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/remove-linked-list-elements/

未看题解的想法

没有想到头节点需要特殊对待

看题解后的想法

1.首先制造一个虚拟头节点,因为如果头节点的值就是val,简单地delete之后,就会找不到剩下的链表元素
2.其次链表删除的操作是这样的:使得该节点的上一个节点的next指向这个节点的next

本题难点

1.理解虚拟头节点
2.自己定义ListNode结构体

代码

/**
 * 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) {}
 * };
 */
// 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* new_head = new ListNode(-1, head);
        // new_head->next = head;
        ListNode* cur = new_head;
        while(cur->next != NULL){
            if(cur->next->val == val){
                ListNode* tmp = cur->next;
                cur->next = cur->next->next;
                delete tmp;
            }else{
                cur = cur->next;
            }
        }
        ListNode* real_head = new_head->next;
        delete new_head;
        return real_head;
    }
};

707.设计链表

链接

(1)文字讲解:https://programmercarl.com/0707.设计链表.html
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/design-linked-list/description/

未看题解的想法

1.经过链表基础,对于虚拟头节点已经理解。
2.但是两个地方错了。
(1)get函数

    int get(int index) {
        if(index > (size-1)){
            return -1;
        }
        ListNode * cur = new_head;
        while(index--){
            cur = cur->next;
        }
        return cur->val;
    }

这里的index是下标,加了虚拟头节点之后,链表下标会➕1,所以比较不合理的index的时候,比较的还是size-1,但是在设置cur的初始值的时候,要设置为new_head->next,而不是上面错误代码中的new_head。
(2)addAtIndex函数

    void addAtIndex(int index, int val) {
        if(index > (size-1)){
            return;
        }
        ListNode* ind_node = new ListNode(val);
        ListNode* cur = new_head;
        while(index--){
            cur = cur->next;
        }
        ind_node->next = cur->next;
        cur->next = ind_node;
        size++;
    }

这里的index是要在这个位置之前加上一个元素,但是链表里加元素,其实重要的是要得到这个index之前的索引(因为你需要改index之前的元素的next)。而且这里的index可以取到size,代表在尾部加,所以比较index合理性的时候要注意,小于等于size-1就行。cur的取值就可以取new_head,因为虚拟头节点的加入,每个元素的index都加一,但是我们这里本来就是要取之前的一个元素,所以从new_head开始取刚好。

看题解后的想法

如上,修改了两个错误的函数取值。
注意虚拟头节点的加入对于index的影响。

本题难点

1.虚拟头节点
2.index变化

代码

class MyLinkedList {
public:
    struct ListNode{
        int val;
        ListNode* next;
        ListNode(int val): val(val), next(nullptr){}
    }; 

    MyLinkedList() {
        new_head = new ListNode(0);
        size = 0;
    }
    
    int get(int index) {
        if(index > (size-1)){
            return -1;
        }
        ListNode * cur = new_head->next;
        while(index--){
            cur = cur->next;
        }
        return cur->val;
    }
    
    void addAtHead(int val) {
        ListNode* tmp = new ListNode(val);
        tmp->next = new_head->next;
        new_head->next = tmp;
        size++;
    }
    
    void addAtTail(int val) {
        ListNode * cur = new_head;
        while(cur->next){
            cur = cur->next;
        }
        ListNode* tail_node = new ListNode(val);
        cur->next = tail_node;
        size++;
    }
    
    void addAtIndex(int index, int val) {
        if(index > size){
            return;
        }
        ListNode* ind_node = new ListNode(val);
        ListNode* cur = new_head;
        while(index--){
            cur = cur->next;
        }
        ind_node->next = cur->next;
        cur->next = ind_node;
        size++;
    }
    
    void deleteAtIndex(int index) {
        if(index > (size-1)){
            return;
        }
        ListNode* cur = new_head;
        while(index--){
            cur = cur->next;
        }
        ListNode* tmp = cur->next;
        cur->next = cur->next->next;
        delete tmp;
        size--;
    }

private:
    ListNode * new_head;
    int size;
};

/**
 * 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);
 */

206.反转链表

链接

(1)文字讲解:https://programmercarl.com/0206.翻转链表.html#思路
(2)视频讲解:
(3)题目链接:https://leetcode.cn/problems/reverse-linked-list/

未看题解的想法

/**
 * 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) {}
 * };
 */
//  struct ListNode{
//     int val;
//     ListNode *next;
//     ListNode(): val(0), next(nullptr){}
//     ListNode(int val): val(val), next(nullptr){}
//     ListNode(int val, ListNode *next): val(val), next(next){}
//  };
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *pre = new ListNode();
        ListNode *cur = head;
        while(cur->next){
            ListNode *temp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = temp;
        }
        cur->next = pre;
        return cur;
    }
};

两个问题:
(1)while(cur->next)
一开始,也想写while(cur),但是我突然脑子短路了,因为最后需要return 头节点,但是如果这样写,退出循环的时候cur是空节点,所以我就写了cur->next,这样退出循环的时候是尾节点,然后处理一下让他指向pre就行。但是,会报错runtime error: member access within null pointer of type ‘ListNode’ (solutio 我输出了一下,很奇怪,到了cur为尾节点的时候就应该退出循环,但是不仅没有退出,next还指向了一个奇怪的地址,我现在还是没搞明白,但是估计和leetcode环境有关。
(2) ListNode *pre = new ListNode()
这样的初始化会使得反转后的链表尾节点多一个0
在这里插入图片描述

看题解后的想法

1.反转链表就是改变next的指向,中间用tmp记录一下原来的next地址,方便遍历
2.ListNode可以直接赋值为NULL
3.可以直接用while(cur)来做循环,然后return pre。这个就不会出现尾节点的next随便指向的问题,很奇怪

本题难点

理解虚拟头节点

代码

版本一

/**
 * 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) {}
 * };
 */
//  struct ListNode{
//     int val;
//     ListNode *next;
//     ListNode(): val(0), next(nullptr){}
//     ListNode(int val): val(val), next(nullptr){}
//     ListNode(int val, ListNode *next): val(val), next(next){}
//  };
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *pre = NULL;
        ListNode *temp = NULL;
        ListNode *cur = head;
        while(cur){
            temp = cur->next;
            cur->next = pre;
            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) {}
 * };
 */
//  struct ListNode{
//     int val;
//     ListNode *next;
//     ListNode(): val(0), next(nullptr){}
//     ListNode(int val): val(val), next(nullptr){}
//     ListNode(int val, ListNode *next): val(val), next(next){}
//  };
class Solution {
public:
    ListNode* reverse(ListNode* pre, ListNode* cur){
        if(cur == NULL) return pre;
        ListNode* tmp = cur->next;
        cur->next = pre;
        return reverse(cur, tmp);
    }
    ListNode* reverseList(ListNode* head) {
        return reverse(NULL, 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) {}
 * };
 */
//  struct ListNode{
//     int val;
//     ListNode *next;
//     ListNode(): val(0), next(nullptr){}
//     ListNode(int val): val(val), next(nullptr){}
//     ListNode(int val, ListNode *next): val(val), next(next){}
//  };
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (head == NULL) return NULL;
        if (head->next == NULL) return head;
        // 这个函数的目的就是要找到尾节点,找到了之后,就开始从后往前反转
        ListNode *last = reverseList(head->next);
        // 使得next的next指向自己(完成反转)
        head->next->next = head;
        // 这个是为了保证翻到最后一个(头节点)的时候他指向NULL
        head->next = NULL;
        // 返回反转后的头节点(原来的尾节点,这就是为啥每次递归都要return last)
        return last;
    }
};
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值