代码随想录算法训练营第三天|203.移除链表元素、707.设计链表、206.反转链表

203.移除链表元素

力扣203

重点在认识到虚头节点的方便性。移除元素时要从这个元素的前一个结点p入手,p->next = p->next->next,另外要创建一个temp指针,把这个temp删掉。

返回时注意返回虚拟头节点的next,而不是直接返回head,因为head可能也会被删,虚拟头节点存在的意义就是使得对头节点的删除操作可以变得和其他节点一样。

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* myhead = new ListNode(0);
        myhead->next = head;
        ListNode* p = myhead;
        while(p->next){
            if(p->next->val==val){
                ListNode* t = p->next;
                p->next = t->next;
                delete t;
            }else
            p = p->next;
        }
        return myhead->next;
    }
};

 707.设计链表

这道题是理解链表的重中之重。

1.定义链表节点结构体

2.初始化链表时要创建虚拟头节点。

3.之后的链表操作基本步骤都是定义cur指向虚拟头结点,然后遍历到正确的位置执行插入或删除。因此要非常注意while的条件,以及步骤之间的执行顺序。

class MyLinkedList {

public:
    struct pNode {
        int val;
        pNode* next;
        pNode(int val):val(val), next(nullptr){}
    };
    MyLinkedList() {
        pHead = new pNode(0);
        size = 0;
    }
    int get(int index) {
        if(index>(size-1)||index<0){
            return -1;
        }
        int i=index;
        pNode* cur = pHead->next;
        while(i--){
            cur = cur->next;
        }
        return cur->val;
    }
    
    void addAtHead(int val) {
        pNode* t = new pNode(val);
        t->next = pHead->next;
        pHead->next = t;
        size++;
    }
    
    void addAtTail(int val) {
        pNode* tail = new pNode(val);
        pNode* cur = pHead;
        while(cur->next){
            cur = cur->next;
        }
        cur->next = tail;
        size++;
    }
    
    void addAtIndex(int index, int val) {
        if(index<=size){
            pNode* t = new pNode(val);//待插入的节点
            pNode* cur = pHead;
            while(index--){
                cur = cur->next;
            }
            t->next = cur->next;
            cur->next = t;
            size++;
        }        
    }
    
    void deleteAtIndex(int index) {
        if(index>(size-1)||index<0){
            return;
        }
        pNode* cur = pHead;
        while(index--){
            cur = cur->next;
        }
        pNode* t = cur->next;
        cur->next = t->next;
        delete t;
        t=nullptr;
        size--;
        
    }
private:
    int size = 0;
    pNode* pHead;
};

/**
 * 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.反转链表

力扣206

这里采用双指针法。

由于最后一个结点的next是NULL,那么反转前的pre也应该赋初值为NULL,而cur指向head;

 

 

我们希望反转方向,让cur->next = pre,但又不能让整个链表断,就需要先用t存储cur->next,然后再让cur->next = pre.

接着让pre和cur都往后移。必须先移pre,不然链表就断了,pre = cur,cur = t,这俩指针都挪到了它后面那个指针的位置。

再看while循环条件,最后结束时,cur指向最后的null,pre指向上图4的位置,也就是新的头结点。也就是while(cur)     和      return  pre;

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* pre = NULL;
        ListNode* cur = head;
        while(cur){//循环结束时cur指向NULL,不需要再动
            ListNode* t = cur->next;
            cur->next = pre;
            pre = cur;
            cur = t;
        }
        return pre;
    }
};

感想:

感觉链表的操作其实都不难,但是很注重一些while填什么,从哪个位置开始,步骤的先后顺序又是什么,需不需要temp指针临时存储以防断连这样的细节。需要我从目的操作出发,遇到问题思考对应的解决方案,弄清楚执行顺序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我知道了。以下是对您的问题的回答: a. 动态分配内存的方法有很多,可以使用C语言的malloc函数,也可以使用C++中的new操作符,具体方法如下: C语言的malloc函数: ```c struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode)); ``` C++中的new操作符: ```c++ ListNode* node = new ListNode(); ``` b. 初始化单链表需要对链表节点的成员变量进行赋值,以下是一个示例: ```c++ struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(NULL) {} }; ListNode* head = NULL; ``` c. 头插法创建单链表的示例代码如下: ```c++ ListNode* head = new ListNode(); head->next = NULL; for (int i = 0; i < n; i++) { int x; cin >> x; ListNode* node = new ListNode(x); node->next = head->next; head->next = node; } ``` 尾插法创建单链表的示例代码如下: ```c++ ListNode* head = new ListNode(); head->next = NULL; ListNode* tail = head; for (int i = 0; i < n; i++) { int x; cin >> x; ListNode* node = new ListNode(x); node->next = NULL; tail->next = node; tail = node; } ``` d. 取链表某一位的值可以通过遍历链表来实现,以下是一个示例: ```c++ ListNode* p = head->next; int pos = 3; for (int i = 1; i < pos && p != NULL; i++) { p = p->next; } if (p == NULL) { cout << "链表长度不足" << endl; } else { cout << p->val << endl; } ``` e. 在链表的某一位进行插入操作可以通过遍历链表找到插入位置,然后插入一个新节点来实现,以下是一个示例: ```c++ ListNode* p = head; int pos = 3; for (int i = 1; i < pos && p != NULL; i++) { p = p->next; } if (p == NULL) { cout << "链表长度不足" << endl; } else { int x = 100; ListNode* node = new ListNode(x); node->next = p->next; p->next = node; } ``` f. 遍历链表可以通过循环遍历链表节点来实现,以下是一个示例: ```c++ ListNode* p = head->next; while (p != NULL) { cout << p->val << " "; p = p->next; } cout << endl; ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值