[TOC]

​ 本文主要记录链表的相关LeetCode题目的实现代码,直接给出本文各个题目的答案,供有需求的读者学习或复制。

一、删除链表的LeetCode题目

1、删除链表中的特定值

203. 移除链表元素(简单难度)

剑指 Offer 18. 删除链表的节点(简单难度)

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        //新建虚拟头结点
        ListNode * myHead = new ListNode(0);
        myHead->next=head;
        //双指针
        ListNode* prev=myHead;//慢指针负责删除节点
        ListNode* cur=prev->next;//当前节点负责确定是否需要删除
        while (cur) {
            // 如果满足条件则执行删除操作;否则慢指针前进一步
            if(cur->val == val) {
                prev->next = cur->next;//删除快指针
            } else {
                prev = cur;//慢指针前进一步
            }
            cur = cur->next;//快指针前进一步
        }
        return myHead->next;
    }
};

83. 删除排序链表中的重复元素(简单难度)

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        // 新建虚拟头结点
        ListNode * myHead=new ListNode(-101);
        myHead->next=head;
        // 快慢指针扫描单链表
        ListNode * prev=myHead;//负责删除
        ListNode * cur=head; // 负责遍历和确定
        while(cur!=nullptr){
            if(cur->val==prev->val){
                prev->next=cur->next;
            }
            else{
                prev=prev->next;
            }
            cur=cur->next;
        }
        return myHead->next;
    }
};

2、只给出待删除元素,实现删除效果

237. 删除链表中的节点(简单难度)

面试题 02.03. 删除中间节点(简单难度)

class Solution {
public:
    void deleteNode(ListNode* node) {
        // node是要删除的节点,将其伪装成下一个节点son
        ListNode* son=node->next;
        node->val=son->val;//伪装其val
        node->next=son->next;//伪装其next
    }
};

3、删除链表中的倒数第N个节点

19. 删除链表的倒数第 N 个结点(中等难度)

剑指 Offer 22. 链表中倒数第k个节点(简单难度)

剑指 Offer II 021. 删除链表的倒数第 n 个结点(中等难度)

方式一:计数法

class Solution {
public:
    ListNode* getKthFromEnd(ListNode* head, int k) {
        // 循环单链表获取len
        int len=0;
        ListNode* p=head;
        while(p){
            p=p->next;
            len++;
        }
        // 循环单链表找到第len-k个元素(倒数第k个==正数第len-k+1)
        int i=0;
        p=head;
        while(p&&i<len-k){
            p=p->next;
            i++;
        }
        return p;
    }
};

方式二:快慢指针法

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* fast=head;
        ListNode* slow=head;
        //先让fast走n步,此时fast可能不存在
        for(int i=0;i<n;i++){
            fast=fast->next;
        }
        //若fast不存在,说明n>链表的长度,则删除掉头结点,保留头结点之后的节点
        if(!fast){
            return head->next;
        }
        //若fast存在,同时遍历
        while(fast->next){
            slow=slow->next;
            fast=fast->next;
        }
        slow->next=slow->next->next;
        
        return head;
    }
};

2095. 删除链表的中间节点(中等难度)

快慢指针法:

class Solution {
public:
    ListNode* deleteMiddle(ListNode* head) {
        ListNode* p=head;
        int len=0;
        while(p){
            p=p->next;
            len++;
        }
        if(len==1) return nullptr;
        if(len==2) {
            head->next=nullptr;
            return head;
        }
        int i=0;
        p=head;
        while(p&&i<len/2-1){
            p=p->next;
            i++;
        }
        p->next=p->next->next;
        return head;
    }
};

4、删除链表中的一段特殊序列

82. 删除排序链表中的重复元素 II(中等难度)

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        // 新建虚拟头结点
        ListNode * myHead=new ListNode(-101);
        myHead->next=head;
        // 快慢指针扫描单链表删除重复元素
        ListNode* p=myHead;//遍历指针,负责遍历
        ListNode * left,*right;//快慢指针,
        while(p->next!=nullptr){
            left=p->next;//保留起始指针
            right=left; //一开始快慢指针相同,比p多一步
            // 尝试移动right,如果right->next存在且和right相同就移动一步,最终right将指向最后一个相同的数
            while(right->next && right->next->val==right->val)
                right=right->next;
            // 如果left==right,说明right没有移动,即没有相同值,p正常移动
            if(left == right) p=p->next;
            // 如果left!=right,说明right有移动,left和right所指的都是相同值
            else p->next=right->next;
        }
        return myHead->next;
    }
};

1171. 从链表中删去总和值为零的连续节点(中等难度)

class Solution {
public:
    ListNode* removeZeroSumSublists(ListNode* head) {
        // 新建虚拟头结点
        ListNode* myHead=new ListNode(0);
        myHead->next=head;
        // 遍历
        ListNode*p=myHead;
        ListNode* left,* right;
        while(p->next!=nullptr){
            left=p->next;
            right=left;
            // 尝试移动right,记录left到right的和作为标准
            int sum=left->val;//[left,right]的元素之和,
            while(right->next){
                // 如果sum为零则退出需要删除节点
                if(sum==0)  break;
                // 如果sum不为零则继续累加直至表尾
                else{
                    right = right->next;//right前进
                    sum += right->val;//right
                }
            }
            if(sum!=0) p=p->next;// 如果sum不为零,p正常移动
            else p->next=right->next; // 如果sum为零,p移动到right的右侧
        }
        return myHead->next;
    }
};

二、反转链表的LeetCode题目

1、反转整个链表

206. 反转链表(简单难度)

剑指 Offer 24. 反转链表(简单难度)

剑指 Offer II 024. 反转链表(简单难度)

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* left=nullptr;
        ListNode* right=head;
        while(right!=nullptr){
            //保存
            ListNode* temp=right->next;
            //反转
            right->next=left;
            //更新
            left=right;
            right=temp;
        }
        return left;
    }
};

2、反转单链表的某个区间

92. 反转链表 II(中等难度)

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        // 新建虚拟头结点
        ListNode* myHead = new ListNode(0);
        myHead->next = head;
        // 慢指针先找到第left-1个节点
        ListNode* slow=myHead;
        int i=0;
        while(slow&&i<left-1){
            slow=slow->next;
            i++;
        }
        if(slow==nullptr) return myHead->next;//说明链表没有要反转的区间,直接返回
        // 慢指针和快指针一起反转[left,right]
        ListNode* rhead=slow->next;//第left个节点(反转序列的头结点)
        // 循环right-left次
        for(int i=left;i<right;i++){
            //保存
            ListNode* temp=rhead->next;//保存rhead的后1步
            rhead->next = temp->next;//rhead重新指向后2步
            //反转
            temp->next = slow->next;//rhead的后1步指向快指针
            //更新
            slow->next=temp;//慢指针指向rhead的后1步
        }
        // 更新头结点
        return myHead->next;
    }
};

3、判断是否是回文链表

234. 回文链表(简单难度)

剑指 Offer II 027. 回文链表(简单难度)

面试题 02.06. 回文链表(简单难度)

class Solution {
public:
    //反转链表
    ListNode* reverse(ListNode* head){
        ListNode* pre=NULL;
        ListNode* temp=NULL;
        ListNode* cur=head;
        while(cur){
            temp=cur->next;
            cur->next=pre;
            pre = cur;
            cur = temp;
        }
        head=pre;
        return head;
    }
    bool isPalindrome(ListNode* head) {
        // 特殊情况
        if (head == NULL || head->next == NULL) {
            return true;
        }
        ListNode* left=head;
        ListNode* right=head;
        //根据快慢指针找到中点,同时出发
        while(right->next&&right->next->next){
            right=right->next->next;//快指针走两步
            left=left->next;//慢指针走一步
        }
        //反转链表的后半部分
        right = reverse(left->next);//right指向后半部分头结点
        left  = head;//left指向前半部分头结点
        //比较链表的前后两部分
        while(right&&left){
            if(right->val!=left->val){
                return false;
            }
            right=right->next;
            left=left->next;
        }
        return true;
    }
};

三、两数相加的LeetCode题目

2. 两数相加(中等难度)

class Solution {
public:
    
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        // 新建结果链表的虚拟头结点
        ListNode* myHead = new ListNode(0);
        // 同时遍历2个可能不等长的链表
        ListNode* cur = myHead;//遍历指针
        int sum = 0;
        bool carry = false; 
        while(l1 != NULL || l2 != NULL){
            sum = 0;
            // 获取链表1的值
            if(l1 != NULL){
                sum += l1->val;
                l1 = l1 -> next;
            }
            // 获取链表2的值
            if(l2 != NULL){
                sum += l2->val;
                l2 = l2 -> next;
            }
            // 如果需要进位则+1
            if(carry) sum++;
            // 为结果链表添加新的元素
            cur -> next = new ListNode(sum % 10);//第一元素
            cur = cur -> next;
            carry = sum >= 10 ? true: false;//发现需要进位
        }
        //如果最后还需要+1位,则需要继续添加一个新结点
        if(carry) cur -> next = new ListNode(1);
        return myHead -> next;
    }
};

445. 两数相加 II(中等难度)

剑指 Offer II 025. 链表中的两数相加(中等难度)

面试题 02.05. 链表求和(中等难度)

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* slow=NULL;//慢指针
        ListNode* fast=head;//快指针
        while(fast!=NULL){
            //保存
            ListNode* temp = fast->next;
            //反转
            fast->next=slow;
            //更新
            slow=fast;
            fast=temp;
        }
        //更新头结点
        head=slow;
        return head;
    }
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* head=new ListNode(-1);//结果链表的虚拟头结点
        ListNode* cur=head;//遍历指针
        l1=reverseList(l1);
        l2=reverseList(l2);
        // 同时遍历2个链表
        int sum=0;
        bool carry=false;//是否需要进位
        while(l1||l2){
            sum=0;
            if(l1!=nullptr){
                sum+=l1->val;
                l1=l1->next;
            }
            if(l2!=nullptr){
                sum+=l2->val;
                l2=l2->next;
            }
            if(carry) sum++;
            // 为结果链表添加一个新的结果
            cur->next=new ListNode(sum%10);
            cur=cur->next;
            carry = sum >= 10 ? true: false;//发现需要进位
        }
        if(carry)   cur->next=new ListNode(1);
        head->next = reverseList(head->next);
        return head->next;
    }
};

附录

1、单链表的C++实现

#include<iostream>
using namespace std;

/*单链表的实现*/
class SingleList{
private:
    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) {}
    };
    ListNode * head;//头结点,头结点可以直接赋值,其他节点必须在上一个节点处添加
public:
    SingleList():head(nullptr){}
    /**增加**/
    void push_front(int value){
        ListNode* newNode= new ListNode(value);
        newNode->next=head;
        head=newNode;
    }
    void push_back(int value){
        ListNode * newNode=new ListNode(value);
        // 如果链表为空添加为头结点
        if(head==nullptr) {
            head=newNode;
            return;
        }
        // 如果链表不为空添加到链表末尾
        else{
            // 遍历找到链表的最后一个节点,注意不能是while(p),因为链表节点的添加必须在上一个节点操作
            ListNode *p=head;
            while(p->next){
                p=p->next;
            }
            p->next=newNode;
        }
    }
    void insert(int index,int value){
        if(index<0) return;
        if(index==0) push_front(value);
        //找到第index个元素
        int i=0;
        ListNode* p=head;
        while(p&&i<index){
            i++;
            p=p->next;
        }
        if(p==nullptr) return;
        //在第index元素后添加新元素
        ListNode* newNode=new ListNode(value);
        newNode->next=p->next;
        p->next=newNode;
    }
    /**删除**/
    void pop_front(){
        if(head!=nullptr){
            ListNode* del = head;
            head=head->next;
            delete del;
        }
    }
    void pop_back(){
        this->erase(this->size()-1);
    }
    // 删除第index个元素
    void erase(int index){
        if(index<0) return;
        if(index==0) pop_front();
        else{
            //尝试找到第index-1个元素,删除其p->next
            ListNode *p=head;
            int i=0;
            while (p&&i<index-1)
            {
                p=p->next;
                i++;
            }
            //没有找到,可能是index超出size
            if(p==nullptr)return;
            //如果找到了且p->next不为空
            if(p->next){
                ListNode * del=p->next;
                p->next=del->next; 
                delete del;
            }
        }

    }
    /**查找**/
    int front(){
        if(head!=nullptr) return head->val;
        return -1;
    }
    int get(int index){
        if(index<0) return -1;
        if(index==0) return front();
        // 遍历找到第index元素,访问其p->val
        int i=0;
        ListNode* p=head;
        while(p&&i<index){
            p=p->next;
            i++;
        } 
        // 如果没有找到
        if(p==nullptr) return -1;
        return p->val;
    }
    int back(){
        return this->get(this->size()-1);
    }
    int size(){
        int len=1;
        ListNode* p=head;
        if(p==nullptr) return 0;
        while(p->next){
            len++;
            p=p->next;
        }
        return len;
    }

    void show(string name=""){
        cout<<name;
        for(ListNode* p=head;p!=nullptr;p=p->next){
            cout<<p->val<<" ";
        }
        cout<<endl;
    }
};

int main()
{
    SingleList* lst=new SingleList();
    lst->push_back(1);
    lst->push_back(2);
    lst->push_back(3);
    lst->push_front(0);
    lst->insert(2,4);
    lst->show("插入后:");
    cout<<"get:"<<lst->get(1)<<endl;
    lst->pop_front();
    lst->erase(1);
    lst->pop_back();
    lst->pop_back();
    lst->pop_back();
    cout<<"len:"<<lst->size()<<endl;
    lst->show("删除后:");


    system("pause");
    return 0;
}

2、双链表的C++实现

#include<iostream>
using namespace std;

/*双链表的实现*/
class DoubleList{
private:
    struct ListNode {
        int val;
        ListNode *next,*prev;
        ListNode() : val(0), next(nullptr),prev(nullptr) {}
        ListNode(int x) : val(x), next(nullptr),prev(nullptr) {}
        ListNode(int x, ListNode *next,ListNode *prev) : val(x), next(next),prev(prev) {}
    };
    ListNode * head,*tail;//头结点指向链表第一个元素;尾结点指向最后一个元素
public:
    DoubleList():head(nullptr),tail(nullptr){}
    /**增加**/
    void push_front(int value){
        ListNode * newNode=new ListNode(value);
        if(head==nullptr){
            head=newNode;
            tail=head;
        }
        else{
            newNode->next=head;
            head->prev=newNode;
            head=newNode;
        }
    }
    void push_back(int value){
        ListNode * newNode=new ListNode(value);
        // 如果尾结点为空添加为尾结点和头结点
        if(tail==nullptr) {
            tail=newNode;
            head=tail;
            return;
        }
        // 如果尾结点不为空添加到尾结点尾部
        else{
            // 遍历找到链表的最后一个节点,注意不能是while(p),因为链表节点的添加必须在上一个节点操作
            newNode->prev=tail;
            tail->next=newNode;
            tail=newNode;
        }
    }
    // 插入第index个元素
    void insert(int index,int value){
        if(index<0) return;
        if(index==0) push_front(value);
        if(index==size()-1) push_back(value);
        // 找到第index个元素
        int i=0;
        ListNode* p=head;
        while(p&&i<index){
            i++;
            p=p->next;
        }
        if(p==nullptr) return;
        // 在index个元素后添加新元素
        ListNode* newNode=new ListNode(value);
        newNode->next=p->next;
        p->next->prev=newNode;
        newNode->prev=p;
        p->next=newNode;
    }
    /**删除**/
    void pop_front(){
        if(head!=nullptr){
            ListNode* del = head;
            head=head->next;
            if(head) head->prev=nullptr; // 如果链表存在2个以上元素
            else tail=nullptr;//如果链表只有一个元素
            delete del;
        }
    }
    void pop_back(){
        if(tail!=nullptr){
            ListNode * del= tail;
            tail=tail->prev;
            if(tail) tail->next=nullptr;
            else head=nullptr;
            delete del;
        }
        
    }
    // 删除第index个元素
    void erase(int index){
        if(index<0) return;
        if(index==0) pop_front();
        if(index==size()-1) pop_back();
        else{
            //尝试找到第index个元素,删除其p->next和p->prev
            ListNode *cur=head;
            int i=0;
            while (cur&&i<index)
            {
                cur=cur->next;
                i++;
            }
            //没有找到,可能是index超出size
            if(cur==nullptr)return;
            //如果找到了且p->next不为空
            ListNode * del=cur;
            ListNode *p=cur->prev;
            p->next=cur->next;
            if(cur->next){
                cur->next->prev=p;
            }
            delete del;
        }

    }
    /**查找**/
    int front(){
        if(head!=nullptr) return head->val;
        return -1;
    }
    int back(){
        if(tail!=nullptr) return tail->val;
        return -1;
    }
    int get(int index){
        if(index<0) return -1;
        if(index==0) return front();
        if(index==size()-1) return back();
        // 遍历找到第index元素,访问其p->val
        int i=0;
        ListNode* p=head;
        while(p&&i<index){
            p=p->next;
            i++;
        } 
        // 如果没有找到
        if(p==nullptr) return -1;
        return p->val;
    }
    
    int size(){
        int len=1;
        ListNode* p=head;
        if(p==nullptr) return 0;
        while(p->next){
            len++;
            p=p->next;
        }
        return len;
    }

    void show(string name=""){
        cout<<name;
        for(ListNode* p=head;p!=nullptr;p=p->next){
            cout<<p->val<<" ";
        }
        cout<<endl;
    }
};

int main()
{
    DoubleList* lst=new DoubleList();
    lst->push_back(1);
    lst->push_back(2);
    lst->push_back(3);
    lst->push_front(0);
    lst->insert(3,4);
    lst->show("插入后:");
    cout<<"get:"<<lst->get(2)<<endl;
    lst->pop_front();
    lst->erase(2);
    lst->pop_back();
    // lst->pop_back();
    // lst->pop_back();
    cout<<"len:"<<lst->size()<<endl;
    lst->show("删除后:");


    system("pause");
    return 0;
}