LeetCode|链表|203.移除链表元素 707.设计链表 206.反转链表

目录

一、203.移除链表元素

1.注意点

2.代码实现

二、707.设计链表

1.代码实现

三、206.反转链表

1.两种思想

2.双指针代码

3.递归代码


一、203.移除链表元素

1.注意点

最好使用一个虚拟头结点,这样删除每个节点的步骤都是一样的。如果不加虚拟头结点,在删除原链表的头结点时,需要单独讨论。

2.代码实现

/**
 * 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* dummyHead = new ListNode(0);//dummyHead为虚拟头结点
        dummyHead->next = head;//令虚拟头结点指向头结点
        ListNode* cur = dummyHead;//这里设置一个新的变量用来移动,dummyHead不动,方便最后返回
        while(cur->next != NULL){
            if(cur->next->val == val){
                ListNode* temp = cur->next;
                cur->next = temp->next;
                delete temp;//释放删除节点的内存
            }
            else{
            cur = cur->next;
            }
        }
        head = dummyHead->next;
        delete dummyHead;//释放虚拟头结点内存
        return head;
    }
};

二、707.设计链表

1.代码实现

class MyLinkedList {
public:
    //创建节点结构体
    struct ListNode{
        int val;
        ListNode* next;
        ListNode(int x):val(x),next(nullptr){}
    };


    MyLinkedList() {
        _dummyHead = new ListNode(0);
        _size = 0;
    }
    
    int get(int index) {
        if(index > (_size - 1) || index < 0){//输入的下标index超出链表长度,或者数值无效
            return -1;
        }
        ListNode* cur = _dummyHead->next;//定义cur临时指针代替dummyHead移动
        while(index){
            cur = cur->next;
            index--;
        }
        return cur->val;
    }
    
    void addAtHead(int val) {
        ListNode* newHead = new ListNode(val);//定义一个新节点,初始化值为val
        newHead->next = _dummyHead->next;
        _dummyHead->next = newHead;
        _size++;//记得将链表节点个数+1
    }
    
    void addAtTail(int val) {
        //首先要找到最后一个节点
        ListNode* cur = _dummyHead;
        while(cur->next != nullptr){
            cur = cur->next;
        }//while循环结束后,cur指向最后一个最后一个节点
        ListNode* newNode = new ListNode(val);
        cur->next = newNode;
        newNode->next = nullptr;
        _size++;//不要忘记修改链表节点个数
    }
    
    void addAtIndex(int index, int val) {
        if(index > _size)
            return;
        //找到index前一个节点
        ListNode* cur = _dummyHead;
        while(index--){
            cur = cur->next;
        }//while循环结束后,cur指向index的前一个节点
        //开始插入元素
        ListNode* newNode = new ListNode(val);
        newNode->next = cur->next;
        cur->next = newNode;
        _size++;//不要忘记修改链表节点个数
    }
    
    void deleteAtIndex(int index) {
        if(index < 0 || index >= _size)//下标无效
            return;
        //找到index前一个节点
        ListNode* cur = _dummyHead;
        while(index--){
            cur = cur->next;
        }
        ListNode* temp = cur->next;//定义临时指针,用来之后内存释放
        cur->next = temp->next;
        delete temp;
        _size--;//不要忘记修改链表节点个数
    }

private:
    int _size;//记录当前链表有多少个节点
    ListNode* _dummyHead;
};

三、206.反转链表

1.两种思想

  1. 双指针思想:简单模拟原链表:1——>2——>3——>NULL。反转链表无非就是改变指向,原本1指向2,那么现在2指向1,1指向NULL。这里定义两个指针cur和pre,cur指向1(初始值为头结点head),pre指向cur的前一个节点(初始值为NULL)。
  2. 递归思想:基于双指针的思想和代码上,实现递归代码。

2.双指针代码

两个要点①改变指向前,需要将后一个节点用临时指针temp保存下来,不然找不到后面的节点了②先更新pre,再更新cur。如果先更新cur,那么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) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* pre = NULL;
        ListNode* cur = head;
        ListNode* temp = NULL;
        while(cur){
            temp = cur->next;//先将cur原本指向的节点保存下来,然后改变指向
            cur->next = pre;//改变指向
            //更新pre和cur位置
            pre =cur;
            cur = temp;
        }
        return pre;
    }
};

3.递归代码

/**
 * 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* reverse(ListNode* pre,ListNode* cur){//定义一个自己的反转两个节点函数
        if(cur == nullptr){//跳出递归语句
            return pre;
        }
        ListNode* temp = cur->next;//定义临时指针保存下一个节点的位置
        cur->next = pre;//改变指向
        return reverse(cur,temp);
    }

    ListNode* reverseList(ListNode* head) {
        return reverse(NULL,head);//相当于双指针思想对于pre和cur的初始化
    }
};

你可能感兴趣的:(LeetCode,链表,数据结构)