链表的基本操作 及力扣典型题型

一、链表基础

链表的类型有三种:单链表、双链表、循环链表

单链表:

双链表:

循环链表: 

 链表与数组的对比:

二、链表结构体的定义

//初始化列表形式
struct ListNode{
    int value;
    ListNode *next;

    ListNode(int v,ListNode *node):value(v),next(node){}
    ListNode(int v):value(v),next(nullptr){}
    ListNode():value(0),next(nullptr){}
       
};

三、创建一个链表

//创建链表方式1
ListNode *head=nullptr;
for(int i=0;i<5;i++){
    head=new ListNode(i,head);
}
ListNode *dummy=new ListNode(0,head);//哑指针

//创建链表方式2
ListNode *head1=new ListNode(1,new ListNode(2,new ListNode(3,nullptr)));
ListNode *dummy1=new ListNode(0,head);//哑指针

四、链表遍历

void print(){
    ListNode* cur=dummy;
    while(cur->next){
        cout<<cur->next->value<<endl;
        cur=cur->next;
    }
    cout<<endl;
}

五、链表其他基本操作(插入、删除、检索)

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

    ListNode* dummy; //哑节点
    int size; //链表大小

    MyLinkedList() {
        dummy=new ListNode(0);
        size=0;
    }
    
    //获取第index个位置链表的值
    int get(int index) { 
        if(index>=size || index<0)  return -1;
        ListNode* head=dummy->next;
        for(int i=0;i<index;i++){
            head=head->next;
        }
        return head->val;
    }
    
    //在链表头插入一个节点
    void addAtHead(int val) {    
        ListNode* head=new ListNode(val,dummy->next);
        dummy->next=head;
        size++;
    }
    
    //在链表尾插入一个节点
    void addAtTail(int val) {    
        ListNode* tail=new ListNode(val);
        ListNode* head=dummy;
        while(head->next){
            head=head->next;
        }
        head->next=tail;
        size++;
    }
    
    //在链表第index个位置前插入一个节点
    void addAtIndex(int index, int val) {    
        if(index>size) return;
        if(index<0) addAtHead(val);
        else if(index==size) addAtTail(val);
        else {
            ListNode* head=dummy;
            for(int i=0;i<index;i++){
                head=head->next;
            }
            ListNode* newnode=new ListNode(val,head->next);
            head->next=newnode;
            size++;
        }
       
    }
    
    //删除链表第index个位置的节点 
    void deleteAtIndex(int index) {
        if(index<0 || index>=size) return;
        ListNode* head=dummy;
        for(int i=0;i<index;i++){
            head=head->next;
        }
        ListNode* del=head->next;
        head->next=head->next->next;
        delete del;
        size--;
    }
};

六、力扣典型链表题

206. 反转链表

//双指针法
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
         ListNode*pre=nullptr;
         ListNode*cur=head;
        while(cur){
            struct ListNode* next=cur->next;
            cur->next=pre;
            pre=cur;
            cur=next;
        }
        return pre;

    }
};

//递归法
class Solution {
public:
    ListNode* reverse(ListNode* pre,ListNode* cur){
        if(!cur) return pre;
        ListNode* next=cur->next;
        cur->next=pre;
        return reverse(cur,next);
    }
    ListNode* reverseList(ListNode* head) {
        return reverse(nullptr,head);
    }
};

142. 环形链表 II

//哈希表
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        unordered_set<ListNode*> hashmap;
        while(head){
            if(hashmap.count(head)) //如果哈希表中有这个节点,说明为环的入口节点
                return head;
            hashmap.emplace(head);
            head=head->next;
        }
        return NULL;
    }
};

//双指针法
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* slow=head;
        ListNode* fast=head;
        while(fast && fast->next){
            slow=slow->next;
            fast=fast->next->next;
            if(slow==fast){ //快慢指针相遇
                ListNode* circlenode=fast;
                ListNode* cur=head;  //从head开始往前走,与circlenode相遇位置就是环的入口
                while(cur!=circlenode){  
                    cur=cur->next;
                    circlenode=circlenode->next;
                }
                return cur;
            }
        }
        return NULL;
    }
};

19. 删除链表的倒数第 N 个结点

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode *dummy=new ListNode(0,head);
        ListNode *fast=head; //注意这快慢指针的设定
        ListNode *slow=dummy;
        for(int i=0;i<n;i++){
            fast=fast->next;
        }
        while(fast){
            fast=fast->next;
            slow=slow->next;
        }
        ListNode *del=slow->next;
        slow->next=slow->next->next;
        delete del;//要在改变链表结构之后删除
        return dummy->next;
    }
};

23. 合并K个升序链表

class Solution {
public:

    ListNode* mergetwo(ListNode* l1,ListNode* l2){
        ListNode* merged=new ListNode(0);
        ListNode* head=merged;
        while(l1&&l2){
            if(l1->val<l2->val){
                merged->next=l1;
                l1=l1->next;
            }
            else {
                merged->next=l2;
                l2=l2->next;
            }
            merged=merged->next;
        }
        merged->next=(l1?l1:l2);
        return head->next;
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        ListNode* result=new ListNode(INT_MIN); //注意INT_MIN,因为有负数
        for(int i=0;i<lists.size();i++){
            result=mergetwo(result,lists[i]);
        }
        return result->next;
    }
};

148. 排序链表

class Solution {
public:
    //链表排序一般使用归并排序
    ListNode* sortList(ListNode* head) {
        return sortList(head,nullptr);
    }
    ListNode* sortList(ListNode* head,ListNode* tail){
        if(head==nullptr){ //注意!!
            return head;
        }
        if(head->next==tail){  //注意!! 
            head->next=nullptr;
            return head;
        }
        ListNode* slow=head;
        ListNode* fast=head;//注意这快慢指针的写法!!
        while(fast!=tail){
            slow=slow->next;
            fast=fast->next;
            if(fast!=tail) fast=fast->next;
        }
        ListNode* mid=slow;
        return merged(sortList(head,mid),sortList(mid,tail));
    }
    ListNode* merged(ListNode* l1,ListNode* l2){
        ListNode* merged=new ListNode(0);
        ListNode* dummy=merged;
        while(l1&&l2){
            if(l1->val<l2->val){
                merged->next=l1;
                l1=l1->next;
            }
            else{
                merged->next=l2;
                l2=l2->next;
            }
            merged=merged->next;
        }
        merged->next=(l1?l1:l2);
        return dummy->next;
    }
};

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
判断一个链表是否是另一个链表的子序列是一道常见的问题。对于这个问题,我们可以使用双指针的方法来解决。双指针一个指向主链表,一个指向子序列链表。我们同时遍历两个链表,比较指针指向的节点是否相同。如果相同,我们就同时向后移动两个指针;如果不相同,我们只移动主链表的指针。当子序列链表遍历完毕时,说明所有的节点都匹配成功,那么它是主链表的子序列;如果主链表遍历完毕,而子序列链表还没有遍历完,说明子序列链表中的节点没有完全匹配,那么它不是主链表的子序列。这种方法的时间复杂度是O(n + m),其中n是主链表的长度,m是子序列链表的长度。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [力扣之判断一个链表是否是回文链表](https://blog.csdn.net/chenbaifan/article/details/121450273)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [[力扣] 203.移除链表元素](https://download.csdn.net/download/weixin_38667920/13759251)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值