链表

一,链表整体逆序

方法一:就地逆置

思路:
在这里插入图片描述

  • 代码
/**
 * 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*new_head=NULL;
        while(head)
        {
            ListNode*next=head->next;
            head->next=new_head;
            new_head=head;
            head=next;
        }
        return new_head;

    }
};

方法二:头插法

1.空间复杂度和常量个数没有关系
2.头节点和头指针的初始化
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* reverseList(ListNode* head) {
        ListNode temp(0);
        while(head)
        {
            ListNode*next=head->next;           
             
            //temp.next=head;//注意先后顺序
            head->next=temp.next;
             temp.next=head;
            head=next;
        }
        return temp.next;
    }
};

作者:xia-mu-lao-zhang-ren
链接:https://leetcode-cn.com/problems/reverse-linked-list/solution/lian-biao-ni-zhi-tou-cha-fa-by-xia-mu-la-ktoi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

二,链表指定位置逆序

(https://leetcode.com/problems/intersection-of-two-linked-lists/description/)

  • 思路
    在这里插入图片描述

1.找到开始逆序的结点,记录它的前驱,用于逆序后的拼接

2.开始逆置,多少个,从哪开始。

3.拼接,注意特殊情况,边界情况

在这里插入图片描述

head为什么到5了,而不是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* reverseBetween(ListNode* head, int left, int right) {
        int chang_len=right-left+1;//计算交换的节点个数
        ListNode*pre_head=NULL;//前驱
        ListNode*result=head;
        while(head&&--left)
        {
            pre_head=head;
            head=head->next; //head移动到交换的节点           
        }
        ListNode*tail=head;
        ListNode*new_head=NULL;
        while(head&&chang_len)//链表逆置
        {
            ListNode*next=head->next;
            head->next=new_head;
            new_head=head;
            head=next;
            chang_len--;
        }
        tail->next=head;//连接
        if(pre_head)
        {
            pre_head->next=new_head;           
        }
        else
        {
            result=new_head;//注意left=1的情况
        }
        return result;
    }
};

作者:xia-mu-lao-zhang-ren
链接:https://leetcode-cn.com/problems/reverse-linked-list-ii/solution/lian-biao-ji-qiao-xiang-guan-by-xia-mu-l-klpk/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

三,求两个链表的交点

在这里插入图片描述
在这里插入图片描述

方法一,使用set求交集

在a中找到和b第一个重复的地址,利用了set的特性

在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
 #include<set>
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        std::set<ListNode*>set_NODE;
        while(headA)
        {
            set_NODE.insert(headA);
            headA=headA->next;
        }
        while(headB)
        {
            if(set_NODE.find(headB)!=set_NODE.end())
                 return headB;
            else
             headB=headB->next;
        }
        return NULL;
    }
};

方法二,空间复杂度O(1)

看图思路很直白
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
 int getLen(ListNode*head)
 {
     int i=0;
     while(head)
     {
         i++;
         head=head->next;
     }
    return i;
 }
 ListNode* forwardLog(int long_len,int short_len,ListNode*head)
 {
     int del=long_len-short_len;
     while(head&&del)//while(del)空指针?
     {
         head=head->next;
         del--;
     }
     return head;
 }
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int a,b;
        a=getLen(headA);
        b=getLen(headB);
        if(a>b)
        {
            headA=forwardLog(a,b,headA);
           
        }
        else
        {
            headB=forwardLog(b,a,headB);
            
        }
        while(headA&&headB)
        {
     if(headA==headB)
            {
                return headA;
            }
            headA=headA->next;
            headB=headB->next;
        }
        return NULL;
    }
};

四,链表求环

leetcode141
在这里插入图片描述

方法一,使用set求环起始节点

在这里插入图片描述

方法二,快慢指针赛跑 【重点】

理解a=c是什么意思
看图中结论
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode*fast;
        ListNode*slow;
        fast=slow=head;
        while(fast)
        {
            fast=fast->next;
            slow=slow->next;
            if(!fast)
            {
                return false;  
            }
            fast=fast->next;
            if(fast==slow)
            {
                return true;
            }
        }
        return false;
     
    }
};

作者:xia-mu-lao-zhang-ren
链接:https://leetcode-cn.com/problems/linked-list-cycle/solution/lian-biao-qiu-huan-by-xia-mu-lao-zhang-r-1lva/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

五,复杂的链表的深度拷贝

LeetCode 138
在这里插入图片描述
在这里插入图片描述

1.map存储的是【原来的】链表地址和序号,使用map是方便后面取出对应地址的序号

2. node_map[ptr]是一个地址

3.node_map[ptr->random]是另一个地址

4.new Node(ptr->val)

看注释,这是构造函数,

Node(int _val) {
val = _val;//他没有,所以要初始化赋值
next = NULL;//他俩都有默认值
random = NULL;

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
public:
    Node* copyRandomList(Node* head) {
      vector<Node*>node_vec;
      map<Node*,int>node_map;
      Node*ptr=head;//从头开始
      int i=0;
      while(ptr)
      {
        node_vec.push_back(new Node(ptr->val));//初始化吗
        node_map[ptr]=i;//键值对,序号和地址
          ptr=ptr->next;
          i++;
      }
      node_vec.push_back(0);//尾结点置空
    ptr=head;//再遍历一遍
    i=0;
    while(ptr)
    {
        node_vec[i]->next=node_vec[i+1];
        if(ptr->random)
        {
            
            int id=node_map[ptr->random];
            node_vec[i]->random=node_vec[id];
        }
        ptr=ptr->next;
        i++;
    }
    return node_vec[0];
    }
};

作者:xia-mu-lao-zhang-ren
链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer/solution/fu-za-de-lian-biao-de-shen-du-kao-bei-by-v8lz/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

当成图进行深度遍历,哈希标记,回溯

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
public:
    unordered_map<Node*,Node*>visited;
    Node* copyRandomList(Node* head) {
        if(head==NULL){
            return NULL;
        }
        if(visited.find(head)!=visited.end()){
            return visited[head];//当前节点已被访问并创造过了,返回它对应的新节点即可
        }
        Node*node=new Node(head->val);
        visited[head]=node;
        node->next=copyRandomList(head->next);
        node->random=copyRandomList(head->random);
        return node;
    }
};

六,排序链表的合并(2个)

LeetCode 21

设置临时头结点的原因【老问题了】

备份头结点,然后往下跑,最后返回头结点

为什么临时头结点不是指针【语法问题】

在这里插入图片描述
在这里插入图片描述

/**
 * 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* mergeTwoLists(ListNode* l1, ListNode* l2) {
    ListNode temp_head(0);
   // new_head->next=nullptr;
    ListNode*new_head=&temp_head;
    while(l1&&l2)
    {
        if(l1->val<l2->val)
        {
            new_head->next=l1;
            l1=l1->next;
          
        }
        else
        {
            new_head->next=l2;
           
            l2=l2->next;
        }   
        new_head=new_head->next;
    }
    if(l1)
    {
        new_head->next=l1;
        
    }
    else if(l2)
    {
        new_head->next=l2;
       
    }
    return temp_head.next;
    }
};

七,排序链表的合并(多个)

LeetCode 23. Merge k Sorted Lists
在这里插入图片描述

方法一,暴力合并

在这里插入图片描述

方法二,排序后合并【有老问题】

  • 注意边界条件 for(int i=1;i<node_vec.size();i++)
  • size和下标差1,下标是从0开始计数,size是从1开始计数
  • 这是老问题了
    在这里插入图片描述
/**
 * 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) {}
 * };
 */
 #include<algorithm>
 bool cmp(const ListNode*a,const ListNode*b)
 {
     return a->val<b->val;
 }
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        vector<ListNode*>node_vec;
        for(int i=0;i<lists.size();i++)
        {
            ListNode*head=lists[i];
            while(head)
            {
                node_vec.push_back(head);
                head=head->next;
            }
        }
        if(node_vec.size()==0)
        {
            return NULL;
        }
        sort(node_vec.begin(),node_vec.end(),cmp);
        for(int i=1;i<node_vec.size();i++)//不懂边界条件设置原因
        {
            node_vec[i-1]->next=node_vec[i];
        }
        node_vec[node_vec.size()-1]->next=NULL;
        return node_vec[0];
    }
};

方法三,分治后相连【重点】

1.分治思想

2.临时头结点的设立【老问题了】

3.return temp.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) {}
 * };
 */

ListNode*mergeTwoLists(ListNode*l1,ListNode*l2)
{
    ListNode temp(0);
    ListNode*head=&temp;
    while(l1&&l2)
    {
        if(l1->val<l2->val)
        {
            head->next=l1;
            l1=l1->next;
        }
        else
        {
            head->next=l2;
            l2=l2->next;
        }
        head=head->next;
    }
    if(l1)
    {
        head->next=l1;
    }
    if(l2)
    {
        head->next=l2;
    }
    return temp.next;//不返回下一个节点,就多了一个头结点了,后面的合并没法算
}

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if(lists.size()==0)
        {
            return NULL;
        }
        if(lists.size()==1)
        {
            return lists[0];
        }
        if(lists.size()==2)
        {
            return mergeTwoLists(lists[0],lists[1]);
        }
        int mid=lists.size()/2;
        vector<ListNode*>sub1_list;
        vector<ListNode*>sub2_list;
        for(int i=0;i<mid;i++)
        {
            sub1_list.push_back(lists[i]);
        }
        for(int i=mid;i<lists.size();i++)
        {
            sub2_list.push_back(lists[i]);
        }
        ListNode*l1=mergeKLists(sub1_list);
        ListNode*l2=mergeKLists(sub2_list);
        return mergeTwoLists(l1,l2);//收口
    }
};

八,链表划分

LeetCode 86. Partition List
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.临时结点的创建【经常犯的语法错误】

设置临时头结点问题
没有初始化,导致后面无法判断空指针

2.后期调用临时结点的成员用什么符号

3.临时结点是空节点,注意尾部处理

4.结点向后移动

    ListNode* partition(ListNode* head, int x) {
        ListNode*more_head;
        ListNode*temp=more_head;//把空给空了
        ListNode*less_head;
        ListNode*pre=less_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) {}
 * };
 */
class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        ListNode more_head(0);
        ListNode less_head(0);
        ListNode *more_ptr=&more_head;
        ListNode*less_ptr=&less_head;
        while(head)
        {
            if(x>head->val)
            {
                less_ptr->next=head;
                less_ptr=head;
            }
            else
            {
                more_ptr->next=head;
                more_ptr=head;//more_ptr=more_next;
            }
            head=head->next;
        }
        more_ptr->next=NULL;//注意置空
        less_ptr->next=more_head.next;//这两个都是空节点
        return less_head.next;
    }
};

九,重排链表

牛客网NC2
在这里插入图片描述

方法一,快慢指针

  • 快满指针找到中间节点
  • 拆分链表,并反转中间节点之后的链表
  • 合并两个链表
class Solution {
public:
    void reorderList(ListNode *head) {
        if(head==NULL||head->next==NULL)
            return;
        ListNode*fast=head;
        ListNode*slow=head;
        while(fast->next!=NULL&&fast->next->next!=NULL){
            fast=fast->next->next;
            slow=slow->next;
        }
        ListNode*after=slow->next;
        ListNode*pre=nullptr;
        slow->next=nullptr;
        while(after){
            ListNode*temp=after->next;
            after->next=pre;
            pre=after;
            after=temp;
        }
        ListNode*first=head;
        after=pre;//复用了变量,自己再写一个也行
        while(first&&after){
            ListNode*f_temp=first->next;
            ListNode*a_temp=after->next;
            first->next=after;
            first=f_temp;
            after->next=first;
            after=a_temp;
        }
    }
};

方法二 ,双端队列

  • 头拿一个,尾拿一个。O(N)时间,O(1)空间
  • 语法问题,初始化一个新节点?
  • 保存结点
class Solution {
public:
    void reorderList(ListNode *head) {
        deque<ListNode*>que;
        ListNode*tmp=head;
        while(tmp){
            que.push_back(tmp);
            tmp=tmp->next;
        }
        ListNode nhead(0);
        ListNode*ntail=&nhead;//这里变成一静一动两个节点了?????
        //ListNode *nhead=new ListNode(0);和上面等效
       // ListNode*ntail=nhead;
        while(!que.empty()){
            ListNode*h=que.front();
            ListNode*t=que.back();
            if(h==t){
                que.pop_back();
                h->next=nullptr;
                ntail->next=h;
                
            }
            else{
                que.pop_front();
                que.pop_back();
                h->next=t;
                t->next=nullptr;
                ntail->next=h;
                ntail=t;
            }
            head=nhead.next;
        }
    }
};
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值