链表/25.K个一组翻转链表21.合并两个有序链表141.环形链表160.相交链表92.反转链表Ⅱ23.合并K个排序链表143.重排链表82.删除排序链表中的重复元素||148.排序链表83.删除排序

92.反转链表Ⅱ

链接:力扣

一刷,四个指针很重要,可以单独拿出来到函数中好理解。

/**
 * 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) {
        ListNode *L=new ListNode(-1);
        L->next=head;
        //有4个指针需要注意,有没有办法一次遍历?
        ListNode *p=L,*p1=nullptr,*p2=nullptr,*p3=nullptr,*p4=nullptr;
        int num=0;
        while(p!=nullptr)
        {
            if(num==left-1)
            {
                p1=p;
                p2=p->next;
            }
            if(num==right)
            {
                p3=p;
                p4=p->next;
                break;
            }
             p=p->next;
             num++;
        }
        reverse_list(p1,p2,p3,p4);
        //cout<<p1->val << " "<<p2->val << " "<<p3->val<< " "<<p4->val<<endl;
        return L->next;


    }
    void reverse_list(ListNode *p1,ListNode *p2,ListNode *p3,ListNode *p4)
     {
         ListNode *slow=p4;
         ListNode *fast=p2;
         while(fast!=p4)
         {
             ListNode *temp=fast;
             fast=fast->next;
             temp->next=slow;
             slow=temp;
         }
         p1->next=slow;
     }
};

25.K个一组翻转链表 

链接:力扣

 跟着一刷走,大概就是每遍历k个就断开,同时记录剩余链表的头节点。

和上面那道题中一样,要反转的链表的前一个结点、要反转链表的第一个节点、要反转链表的最后一个节点、要反转链表的尾节点的下一个节点(同时也是下一个要反转链表的头节点),要特别注意。

/**
 * 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* reverseKGroup(ListNode* head, int k) {

        //设置头节点
        ListNode *L=new ListNode(-1);
        L->next=head;
    
        
         //遍历反转
         ListNode *pre=L;
         ListNode *start=pre->next;
         ListNode *end=pre;
         int t=k;
         while(end!=nullptr)//这里为什么是end->next,因为想得到的是k个链表中最后一个节点,如果是end!=null 则到了下一个链表中的第一个节点
         {
             t=k;
             while(end!=nullptr && t)
             {
                 end=end->next;
                 t--;
             }
             if(end==nullptr)//如果end为nullptr,说明不满k个,最后保持原状
             {
                 break;
             }
             ListNode *nextstart=end->next;
             end->next=nullptr;//这个特别重要,必须断开,不然函数内无法执行
             pre->next=ReverseList(start);
             start->next=nextstart;

             pre=start;
             start=nextstart;
             end=pre;
         }

         return L->next;
    }

    ListNode *ReverseList(ListNode *start)
    {
        ListNode *slow=nullptr,*fast=start;
         while(fast!=nullptr)
        {
            ListNode *temp=fast;
            fast=fast->next;
            temp->next=slow;
            slow=temp;
        }
        return slow;

    }
};

1、四个节点,且end节点必须从pre开始,而不是start开始

2、每次反转,先让end去探路,如果小于k个,则break

3、反转链表前,必需让end->next=nullptr ,链表断开再反转。否则无法使用ReverseList函数。

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* list1, ListNode* list2) {
        ListNode *L=new ListNode(-1);
        ListNode *r=L;
        ListNode *p1=list1,*p2=list2;
        while(p1!=nullptr && p2!=nullptr)
        {
            if(p1->val<p2->val)
            {
                r->next=p1;
                p1=p1->next;
            }
            else
            {
                r->next=p2;
                p2=p2->next;
            }
            r=r->next;
        }
        if(p1!=nullptr)
        {
            r->next=p1;
        }
        else
        {
            r->next=p2;
        }
        return L->next;
        
    }
};

 23.合并K个排序链表

链接:力扣

 看题解,就很牛,竟然能是优先队列,还是印象模模糊糊的

/**
 * 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:
    struct cmp{
        bool operator() (ListNode* &node1,ListNode* &node2)//建立一个小根堆
        {
            return node1->val>node2->val;
        }
    };
    ListNode* mergeKLists(vector<ListNode*>& lists) {//把整个链表放入优先队列
        priority_queue<ListNode*,vector<ListNode*>,cmp>q;
        for(auto list:lists)
        {
          if(list!=nullptr)
          {
              q.push(list);
          }
            
        }
        ListNode *h=new ListNode(-1),*r=h;
        while(!q.empty())
        {
           ListNode *temp=q.top();//temp既是链表头结点,又是整个链表
            r->next=temp;
           temp=temp->next;//该链表的头结点换成第二个
           q.pop();//把原先的头结点pop掉
           if(temp!=nullptr)
           {
               q.push(temp);
           }
           r=r->next;
        }
        return h->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) {}
 * };
 */
 /*
 解法关键词:优先队列
 由于每次希望得到的是当前所有链表所有节点的最小值,故应该是小根堆,
 优先队列默认大根堆,但是这里要自定义优先写法,因为优先队列中放入的是每个链表的头节点
 优先队列就是巧妙地利用了链表头节点既是一个节点,又是一个链表的特性。
 */
class Solution {
public:
struct myCompare{
    bool operator()(ListNode * &a,ListNode * &b)
    {
        return a->val>b->val;//小根堆是>号?
    }

};
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        priority_queue<ListNode*,vector<ListNode*>,myCompare>pQueue;

        for(auto headnode:lists)
        {
            if(headnode!=nullptr)
            {
                 pQueue.push(headnode);
            }
           
        }
        ListNode *L=new ListNode(-1);
        ListNode *r=L;
        while(!pQueue.empty())
        {
            ListNode *temp=pQueue.top();//取出所有链表中头节点最小的,即最小节点 
            pQueue.pop();//删除拥有最小头结点的链表        
            r->next=temp;//把最小头节点连接到要求得合并链表
            r=r->next;

            temp=temp->next;//拥有最小头结点的链表,往下走一个节点,再把这个更新后的链表扔进小根堆
            if(temp!=nullptr)
            {
                pQueue.push(temp);
            }
        }
        return L->next;

    }
};

141.环形链表

链接:力扣

 

 

/**
 * 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) {
        if(head==nullptr || head->next==nullptr)
        {
            return false;
        }
        ListNode *slow=head;
        ListNode *fast=head->next;
        while(fast!=nullptr && fast->next!=nullptr)
        {
            slow=slow->next;
            fast=fast->next->next;
            if(slow==fast)
            {
                return true;
            }
        }
        return false;
        
    }
};

 60.相交链表

链接:

 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        //快慢指针
        ListNode *p1=headA;
        ListNode *p2=headB;
        int lenA=0,lenB=0;
        while(p1!=nullptr)
        {
            p1=p1->next;
            lenA++;
        }
         while(p2!=nullptr)
        {
            p2=p2->next;
            lenB++;
        }
        int n=abs(lenA-lenB);
        p1=headA,p2=headB;
        if(lenA>lenB)
        {
            while(n)
            {
                p1=p1->next;
                n--;
            }
        }
        else
        {
             while(n)
            {
                p2=p2->next;
                n--;
            }

        }
        while(p1 && p2)
        {
            if(p1==p2)
            {
                return p1;
            }
            p1=p1->next;
            p2=p2->next;
        }
        return nullptr;

        
    }
};

 

 141.环形链表II

链接:力扣

 做过很多遍了,这次没有做

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
 /*
 有一道题印象深刻,判断两个链表相交的位置。突然发现是这道题!真尴尬
 基本思路:
 先让fast节点多走两步,!!fast指针是一步走两个节点,slow指针一步走一个节点
 然后fast和slow必然在环内相交。记住环内相交节点,然后让第三个指针从链表起始节点出发,相交节点指针和起始指针同步出发,来到环的入口节点
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(head==nullptr || head->next==nullptr)
        {
            return nullptr;
        }
        ListNode *fast=head,*slow=head;
        while(fast!=nullptr && fast->next!=nullptr)
        { 
            slow=slow->next;
            fast=fast->next->next;
            if(slow==fast)//说明有环
            {
               //cout<<"有环"<<endl;
                ListNode *p=head;
                while(p!=slow)
                {
                    p=p->next;
                    slow=slow->next;
                }
                return slow;

            }
        }
        return nullptr;
        
        
    }
};

143.重排链表 

链接: 

 震惊,基本思路是先反转后半部分,再合并

/**
 * 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:
    void reorderList(ListNode* head) {
        if(head->next!=nullptr)
        {
             ListNode *L=new ListNode(-1);
        L->next=head;

        int len=0;
        ListNode *p=head;
        while(p!=nullptr)
        {
            p=p->next;
            len++;
        }

        int t=len/2;
        p=L;
        while(p!=nullptr && t)
        {
            p=p->next;
            t--;
        }
        cout<<p->val<<endl;

        ListNode *nextstart=p->next;
        p->next=nullptr;

        //反转后半截链表
       ListNode *List2= ReverseList(nextstart);

      /* 调试
      PrintList(L->next);
       cout<<"============="<<endl;
       PrintList(List2);*/

       //合并链表,r为新链表指针

       ListNode *p1=L->next, *p2=List2,*r=L;
       int flag=0;

       while(p1 && p2)
       {
           if(flag)
           {
               r->next=p2;
               p2=p2->next;
               flag=0;
           }
           else
           {
               r->next=p1;
               p1=p1->next;
               flag=1;
           }
           r=r->next;
       }
       r->next=p2;
       head= L->next;

        }
       

        

    }
     ListNode* ReverseList(ListNode *fast)
    {
        ListNode *slow=nullptr;
        while(fast!=nullptr)
        {
          ListNode *temp=fast;
          fast=fast->next;
          temp->next=slow;
          slow=temp; 
        }
        return slow;
    }
    void PrintList(ListNode *l)
    {
        ListNode *p=l;
        while(p!=nullptr)
        {
            cout<<p->val<<" ";
            p=p->next;
            
        }
        cout<<endl;
    }
};

 寻找中点不需要多遍历一遍,用快慢指针即可

class Solution {
public:
    void reorderList(ListNode* head) {
        if (head == nullptr) {
            return;
        }
        ListNode* mid = middleNode(head);
        ListNode* l1 = head;
        ListNode* l2 = mid->next;
        mid->next = nullptr;
        l2 = reverseList(l2);
        mergeList(l1, l2);
    }

    ListNode* middleNode(ListNode* head) {
        ListNode* slow = head;
        ListNode* fast = head;
        while (fast->next != nullptr && fast->next->next != nullptr) {
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }

    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr;
        ListNode* curr = head;
        while (curr != nullptr) {
            ListNode* nextTemp = curr->next;
            curr->next = prev;
            prev = curr;
            curr = nextTemp;
        }
        return prev;
    }

    void mergeList(ListNode* l1, ListNode* l2) {
        ListNode* l1_tmp;
        ListNode* l2_tmp;
        while (l1 != nullptr && l2 != nullptr) {
            l1_tmp = l1->next;
            l2_tmp = l2->next;

            l1->next = l2;
            l1 = l1_tmp;

            l2->next = l1;
            l2 = l2_tmp;
        }
    }
};

作者:力扣官方题解
链接:https://leetcode.cn/problems/LGjMqU/solutions/1037737/zhong-pai-lian-biao-by-leetcode-solution-wm25/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

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

链接:力扣

 解法,这个写了很多次,这次没有刷

/**
 * 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 {
    /*
    以第一个为例,删除链表的倒数第2个节点相当于找到正数第三个节点
                               3                    2
                               n                    len-n
    让fast指针先走n步,然后slow再和fast一起走
    */
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        if(head==nullptr )
        {
            return head;
        }
        ListNode *L=new ListNode(-1);
        L->next=head;
        ListNode *fast=L,*slow=L;
        n++;
        while(n && fast!=nullptr)
        {
             fast=fast->next;
             n--;
        }
        
       

        while(fast!=nullptr)
        {
            slow=slow->next;
            fast=fast->next;
        }
         
        if(slow!=nullptr && slow->next!=nullptr)
        {
            slow->next=slow->next->next;
        }
        return L->next;

    }
};

82.删除排序链表中的重复元素|| 中等--------这道题第二遍了还是有些吃力

链接:力扣

错误解法:

/**
 * 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* deleteDuplicates(ListNode* head) {
       if(head==nullptr)
        {
            return nullptr;
        }
        ListNode *L=new ListNode(-1);
        L->next=head;
        ListNode *pre=L,*start=L->next,*end=L->next;
        while(end!=nullptr)
        {
            int temp=start->val;
            end=start->next;
            
            while(end!=nullptr && end->val==temp)
            {
                endpre=end;
                end=end->next;
            }
            start=end;
            pre->next=start;//删除重复节点
            pre=endpre;//上一个链表的最后一个节点

            //下一个循环
            end=pre;

        }
        return L->next;

    }
};

正确解法:

重点:按照有无重复节点,分类讨论。另外也可以设置pre ,start,end=start->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) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
       if(head==nullptr)
        {
            return nullptr;
        }
        ListNode *L=new ListNode(-1);
        L->next=head;
        ListNode *pre=L,*start=L->next,*end=L->next;
        while(end!=nullptr)
        {
            int temp=start->val;
            end=start->next;
            if(end!=nullptr && end->val==temp)//有重复元素
            {
                while(end!=nullptr && end->val==temp)
                {
                    end=end->next;
                }
                pre->next=end;
                start=end;

            }
            else//没有重复元素
            {
                pre=start;
                start=start->next;
            }
            
            

        }
        return L->next;

    }
};

速刷剑指offer

 

83.删除排序链表中的重复元素 ----简单

链接:力扣

 这个快慢指针比较快,但是我还是延续了上一次的思路。

一刷:

/**
 * 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* deleteDuplicates(ListNode* head) {
        if(head==nullptr)
        {
            return nullptr;
        }

        
        ListNode *slow=head,*fast=head->next;
    
        while(fast!=nullptr)
        {
            if(fast->val==slow->val)
            {
                fast=fast->next;
            }
            else
            {
                slow->next=fast;
                slow=fast;
                fast=fast->next;
            }
        }
       slow->next=fast;
       return 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* deleteDuplicates(ListNode* head) {
        ListNode *L=new ListNode(-1);
        L->next=head;
        ListNode *pre=L, *fast=L->next;
        while(fast!=nullptr)
        {
            while(fast!=nullptr && fast->next!=nullptr&& fast->val==fast->next->val)
            {
                fast=fast->next;
            }
            pre->next=fast;
            pre=fast;
            if(fast==nullptr)
            {
                break;
            }
            fast=fast->next;
        }
        return L->next;



    }
};

a

 148.排序链表 中等

链接:力扣

 

 题解看这篇:力扣

链表的归并排序,真是丧心病狂

 

要写两个函数,cut(链表,n),把链表的前n个cut下来

                          merge(链表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 {
/*
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序
*/
public:
    ListNode* sortList(ListNode* head) {
        ListNode *L=new ListNode(-1);
        L->next=head;
        
        //计算链表长度
        int len=0;
        ListNode *p=L->next;
        while(p!=nullptr)
        {
            p=p->next;
            len++;
        }

        //归并排序,cut函数将链表 l 切掉前 n 个节点,并返回后半部分的链表头。
        
        for(int cutsize=1;cutsize<len;cutsize=cutsize*2)
        {
           ListNode *tail=L;
           ListNode *nextList=tail->next;
           while(nextList!=nullptr)
           {
                ListNode *list1=nextList;
               // cout<<"nextList->val    "<<nextList->val<<endl;
               // cout<<"list1->val    "<<list1->val<<endl;
                ListNode *list2=cut(list1,cutsize);//把头为list1数cutsize个节点cut出去,返回cut完后,后半截的头
                nextList=cut(list2,cutsize);

                /*调试
                printL(list1);
                printL(list2);
                printL(nextList);*/
              
                
                tail->next=MergeSort(list1,list2);
                while(tail->next!=nullptr)
                {
                    tail=tail->next;
                }
               // cout<<"========================="<<endl;
           }
            


        }
        return L->next;

    }
    ListNode *cut(ListNode *l,int n)//必须断开,最后一个元素指向空
    {
       ListNode *p=l;
       n--;//为了找到末尾节点而不是下一个链表头节点
        while(p&& n)
        {
            p=p->next;
            n--;
        }
        if(p==nullptr)
        {
            return nullptr;
        }
        ListNode *nextl=p->next;
        p->next=nullptr;
        return nextl;
    }

    ListNode *MergeSort(ListNode *l1,ListNode *l2)
    {
        //先整一个头结点;
        ListNode *temp=new ListNode(-1);
        temp->next=l1;
        ListNode *p1=l1,*p2=l2,*r=temp;
        while(p1&& p2)
        {
            if(p1->val<p2->val)
            {
                r->next=p1;
                p1=p1->next;
            }
            else
            {
                r->next=p2;
                p2=p2->next;
            }
            r=r->next;
        }
        if(p1)
        {
            r->next=p1;
        }
        else
        {
            r->next=p2;
        }
        return temp->next;
        
    }


};

a

a

24.两两交换链表中的节点 中等 -------再刷还是容易忘,哭哭

链接:力扣

又是麻花君,又见麻花君

 首先这个麻花涉及四个节点,同时有一个节点是头节点,所以实际上是三个节点

是个4个节点上的均匀麻花

然后pre一次走一步,pre=temp;

/**
 * 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) {}
 * };
 */
 /*
  首先这个麻花涉及四个节点,同时有一个节点是头节点,所以实际上是三个节点

是个4个节点上的均匀麻花

然后pre一次走一步,pre=temp;
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(head==nullptr || head->next==nullptr)
        {
            return head;
        }
        //头节点
        ListNode *L=new ListNode(-1);
        L->next=head;

        ListNode *cur=L;
        while(cur!=nullptr && cur->next!=nullptr && cur->next->next!=nullptr)
        {
            ListNode *temp=cur->next;
            ListNode *temp1=cur->next->next->next;

            cur->next=temp->next;
            cur->next->next=temp;
            temp->next=temp1;

            cur=temp;

        }
        return L->next;

    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值