链表--刷题记录

1、反转指针

【题目】
反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

运用了迭代的方法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        stack<ListNode*> temp;
        ListNode *pre=NULL;
        ListNode *cur=head;
        while(cur!=NULL)
        {
            ListNode*next=cur->next;

            cur->next=pre;
            pre=cur;
            cur=next;
        }
        return pre;


    }
};

2、反转链表II

Leetcode92
【题目】
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

说明:
1 ≤ m ≤ n ≤ 链表长度。

示例:

输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

主要的是记录反转前的指针位置和反转后的指针的位置,连接处指针如何处理。学到了查找指针位置,可以用while循环–实现,还是要通过画图注意好细节的地方。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

上代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        ListNode * cur=head;
        ListNode * pre=NULL;
        ListNode* Left;
        ListNode* Tail;

        if(head==NULL)
            return NULL;
        while(m>1)  //cur移动到开始转换的位置,pre移动到转换的前一个位置
        {
            pre=cur;
            cur=cur->next;
            m--;
            n--;
        }
        Left=pre;
        Tail=cur;
        ListNode* next=NULL;
        while(n>0)  //一直反转 m--n的链表
        {
            next=cur->next;
            cur->next=pre;
            pre=cur;
            cur=next;
            n--;
        }

        if(Left!=NULL)
        {
            Left->next=pre;
        }
        else
        {
            head=pre;
        }
        Tail->next=cur;

        return head;
        
    }
};

3、删除排序链表中的重复元素

Leetcode 83
【题目】
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

示例 1:

输入: 1->1->2
输出: 1->2
示例 2:

输入: 1->1->2->3->3
输出: 1->2->3

题解中的方法是比较前一个元素和后一个元素是否相同,是因为这个链表是有序的,我用了查找表的方法去做。
上代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        unordered_map<int,int> record;
        ListNode *cur,*pre;
        cur=head;
        pre=NULL;
        
        while(cur!=NULL)
        {
            if(record.find(cur->val)==record.end())  //没有重复
            {
                record[cur->val]++;
                pre=cur;
                cur=cur->next;
            }
            else //是重复的元素
            {
                pre->next=cur->next;
                //delete cur;
                cur=cur->next;
            }
        }
        return head;
    }
};

4、分隔链表

Leetcode 86
【题目】
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。

你应当保留两个分区中每个节点的初始相对位置。

示例:

输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5

我是用两个容器存储了结点。然后把大于和小于的结点整合起来。
上代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        vector<ListNode*> Small;
        vector<ListNode*> Biger;
        ListNode *cur=head;
        ListNode* begin=NULL;
        if(cur==NULL)
        return begin;
        while(cur!=NULL)
        {
            if(cur->val<x)
            {
                Small.push_back(cur);
                cur=cur->next;
            }
            else
            {
                Biger.push_back(cur);
                cur=cur->next;
            }
        }
        if(Small.size()>0)
        {
            begin=Small[0];
            int i;
            for(i =0 ; i< Small.size()-1; i++)
            {
                Small[i]->next=Small[i+1];
            }
            if(Biger.size()>0)
            {
                Small[i]->next=Biger[0];
                for(int i = 0 ; i< Biger.size()-1;i++)
                {
                    Biger[i]->next=Biger[i+1];
                }
                Biger[Biger.size()-1]->next=NULL;

            }

            return begin;

        }
        else
        {
            begin=Biger[0];
            for(int i = 0 ; i< Biger.size()-1;i++)
            {
                Biger[i]->next=Biger[i+1];
            }
            Biger[Biger.size()-1]->next=NULL;
            return begin;
        }
              
    }
};

然后看题解,用的是两个链表,但是用的是在头部添加两个哑结点,然后后移一位就行了。嗯,我没有想到,把这个代码也贴出来,是Java的代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode partition(ListNode head, int x) {
        ListNode minLink = new ListNode(0);//记录小值链表的头
        ListNode minP = minLink;//对小表操作用的指针

        ListNode maxnLink = new ListNode(0);//记录大值链表的头
        ListNode maxP = maxnLink;//同理

        while(head!=null){
            if(head.val < x){//找到小的值

                minP.next = head;//放入minLink中,操作指针后移一位
                minP = head;

            }else{

                maxP.next = head;//放入maxLink中,操作指针后移一位
                maxP = head;

            }
            head = head.next;
        }
        //遍历完成后记得后一段链表的最后节点指向null;
        maxP.next = null;
        //两段拼接
        minP.next = maxnLink.next;

        return minLink.next; 
    }
}


5、奇偶链表

Leetcode 328
【题目】

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。

示例 1:

输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL

示例 2:

输入: 2->1->3->5->6->4->7->NULL
输出: 2->3->6->7->1->5->4->NULL
说明:

应当保持奇数节点和偶数节点的相对顺序。
链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        ListNode Odd(0);
        ListNode* Odd_Pre=&Odd;
        ListNode Eve(0);
        ListNode* Eve_Pre=&Eve;
        int m=0;
        if(head==NULL)
            return NULL;
        while(head!=NULL)
        {
            if(m++%2==0)
            {
                Odd_Pre->next=head;
                Odd_Pre=head;
                head=head->next;
            }
            else
            {
                Eve_Pre->next=head;
                Eve_Pre=head;
                head=head->next;
            }
            
           // m++;

        }
        Eve_Pre->next=NULL;
        Odd_Pre->next=Eve.next;
        return Odd.next;

    }
};

还有一种

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        ListNode Odd(0);
        ListNode* Odd_Pre=&Odd;
        ListNode Eve(0);
        ListNode* Eve_Pre=&Eve;
        ListNode*cur=head;
        int m=0;
        if(head==NULL)
            return NULL;
        while(cur!=NULL)
        {
            
                Odd_Pre->next=cur;
                Odd_Pre=cur;
                Eve_Pre->next=Odd_Pre->next;
                Eve_Pre=Odd_Pre->next;
                if(Eve_Pre!=NULL)
                    cur=Eve_Pre->next;
                    else
                    break;
           // m++;

        }
        Eve_Pre=NULL;
        Odd_Pre->next=Eve.next;
        return Odd.next;

    }
};

这个时间和内存更低了

还有一种是双指针,还是挺巧妙的

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        if(head==NULL)
            return NULL;
        ListNode *Odd=head,*Eve=head->next,*EveHead=Eve;
        while(Eve!=NULL&&Eve->next!=NULL)
        {
            Odd->next=Eve->next;
            Odd=Odd->next;
            Eve->next=Odd->next;
            Eve=Eve->next;
            


        }
        Odd->next=EveHead;
        return head;

    }
};

6、两数相加II

Leetcode 445
【题目】
给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。

进阶:

如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。

示例:

输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 8 -> 0 -> 7

我用了三个栈,然后遍历最后一个栈

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        stack<int> L1;
        stack<int> L2;
        stack<int> S;
        
        ListNode*cur1=l1;
        ListNode*cur2=l2;
        

        while(cur1!=NULL)
        {
            L1.push(cur1->val);
            cur1=cur1->next;
        }
        while(cur2!=NULL)
        {
            L2.push(cur2->val);
            cur2=cur2->next;
        }
        int count=0;

        int num1;
        int num2;
        while(!L1.empty()&&!L2.empty())
        {
            num1=L1.top();
            L1.pop();
            num2=L2.top();
            L2.pop();
            S.push((num1+num2+count)%10);
            count=(num1+num2+count)/10;
        }
        while(!L1.empty())
        {
            num1=L1.top();
            L1.pop();
            S.push((num1+count)%10);
            count=(num1+count)/10;

        }
        while(!L2.empty())
        {
            num2=L2.top();
            L2.pop();
            S.push((num2+count)%10);
            count=(num2+count)/10;
        }
        if(count!=0)
        {
            S.push(count);
        }
        int num=S.top();
        S.pop();
        ListNode* pre=new ListNode(num);
        ListNode* cur=pre;
        while(!S.empty())
        {
            int num=S.top();
            S.pop();
            ListNode* p=new ListNode(num);
            cur->next=p;
            cur=p;

        }
        return pre;

        

    }
};

还有就是在计算的时候用保存在链表里面,链表的那个指针写的还是很好的

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        stack<int> L1;
        stack<int> L2;
        
        ListNode*cur1=l1;
        ListNode*cur2=l2;       

        while(cur1!=NULL)
        {
            L1.push(cur1->val);
            cur1=cur1->next;
        }
        while(cur2!=NULL)
        {
            L2.push(cur2->val);
            cur2=cur2->next;
        }
        int count=0;

        int num1;
        int num2;
        ListNode* res=nullptr;
        while(!L1.empty()||!L2.empty()||count!=0)
        {
            if(!L1.empty())
            {
                num1=L1.top();
                L1.pop();
            }
            else
            num1=0;
            if(!L2.empty())
            {
                num2=L2.top();
                L2.pop();
            }
            else
            num2=0;
            auto cur=new ListNode((num1+num2+count)%10);
            count=(num1+num2+count)/10;
            cur->next=res;
            res=cur;
        }
        return res;
    }
};

7、删除排序链表中重复元素II

Leetcode 82
【题目】
给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。

示例 1:

输入: 1->2->3->3->4->4->5
输出: 1->2->5

示例 2:

输入: 1->1->1->2->3
输出: 2->3

用了三个指针,表示当前访问结点的前后数据,如果前后都没有相同元素,则将指针插入到链表中。这题的重点是使用虚拟头结点。
上代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        ListNode *dummyhead = new ListNode(0);
       // dummyhead->next=head;
        ListNode *cur;
        ListNode *pre;
        ListNode *n;
        ListNode *f;
        if(head==NULL)
        return NULL;
        f=dummyhead;       
        pre=head;
        cur=head->next;
        if(head->next==NULL)
        return head;
        if(pre->val!=cur->val)
        {
            f->next=pre;
            f=f->next;
        }
        n=cur->next;     
        while(cur->next!=NULL)
        {
            
            if(cur->val!=pre->val&&cur->val!=n->val)
            {
                f->next=cur;
                f=f->next;
            }
            
            pre=cur;
            cur=n;
            n=n->next;

        }
        if(cur->val==pre->val)
        {
            f->next=NULL;
        }
        else
        {
            f->next=cur;
        }

        return dummyhead->next;
        
    }
};

还用两种方法,相比之下,我用的方法就有点复杂
在这里插入图片描述

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        ListNode* dummyhead = new ListNode(-1);
        dummyhead -> next = head;
        ListNode* p = dummyhead;
        while(p -> next && p -> next -> next){
            bool tag = false;           //标志位记录p后面是否经过处理
            while(p -> next -> next && p -> next -> val == p -> next -> next -> val){
                tag = true;
                p -> next -> next = p -> next -> next -> next;
            }
            if(tag){
                p -> next = p -> next -> next;
            }
            else{
                p = p -> next;
            }
        }
        return dummyhead -> next;
    }
};

在这里插入图片描述

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if(head == NULL || head -> next == NULL){
            return head;
        }
        bool tag = false;           //记录当前head结点值是否重复
        while(head -> next && head -> val == head -> next -> val){
            tag = true;
            head = head -> next;
        }
        head -> next = deleteDuplicates(head -> next);
        if(tag) {
            return head -> next;
        }
        else {
            return head;
        }
    }
};

8、合并两个有序链表

Leetcode 21
【题目】
将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

添加虚拟头结点,用两个指针移动位置

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* dummyHead1= new ListNode(0);
        ListNode* dummyHead2= new ListNode(0);

        ListNode* cur1=l1;
        ListNode* cur2=l2;
        ListNode* f=dummyHead1;

        while(cur1!=NULL&&cur2!=NULL)
        {
            if(cur1->val<=cur2->val)
            {
                f->next=cur1;
                f=f->next;
                cur1=cur1->next;
            }
            else
            {
                f->next=cur2;
                f=f->next;
                cur2=cur2->next;
            }
        }  
        while(cur1!=NULL)
        {
            f->next=cur1;
            f=f->next;
            cur1=cur1->next;

        }     
        while(cur2!=NULL)
        {
            f->next=cur2;
            f=f->next;
            cur2=cur2->next;
        }  
        f->next=NULL;
        return dummyHead1->next;
    }
};

在链表的题目一般有两种方法,一是迭代,二是递归
我一般会选择迭代,递归想法有点难想到,但是递归的核心就是结束条件。我看到的题解里面递归写的还不错啊,Nice~~~

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if (l1 == nullptr) {
            return l2;
        } else if (l2 == nullptr) {
            return l1;
        } else if (l1->val < l2->val) {
            l1->next = mergeTwoLists(l1->next, l2);
            return l1;
        } else {
            l2->next = mergeTwoLists(l1, l2->next);
            return l2;
        }
    }
};


9、两两交换链表中的节点

Leetcode 24
【题目】
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例:

给定 1->2->3->4, 你应该返回 2->1->4->3

设立虚拟节点,然后用指针,主要是画图要清楚

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummyHead= new ListNode(0);
        ListNode* p= dummyHead;
        p->next=head;
        while(p->next!=NULL&&p->next->next!=NULL)
        {
            ListNode *n1=p->next;
            ListNode *n2=p->next->next;
            ListNode *n3=n2->next;

            p->next=n2;
            n2->next=n1;
            n1->next=n3;
            
            p=n1; //n3的上一个节点是n1这个要注意
        }
        return dummyHead->next;
    }
};

10、K个一组翻转链表

Leetcode 25
【题目】
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

示例:

给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5

主要用了递归的想法,但是我困在了递归如何开始的地方了,其实本质上就是对递归不是很了解,就把该函数的递归过程看做一个子过程就好了。

上代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        int m=0;
        ListNode* cur=head;
  
        while(cur!=NULL)
        {
            if(++m>=k)
                break;
            cur=cur->next;
        }
        if(m<k)
        {
            return head;
        }
        
            ListNode* pre=NULL;
            ListNode* curr=head;
            for(int i = 0 ; i< k ; ++i)
            {
                auto node=curr->next;
                curr->next=pre;
                pre=curr;
                curr=node;
            }
  
            head->next=reverseKGroup(curr,k);
        

        return pre;
        
        
    }
    
};

11、删除链表中的结点

Leetcode 237
【题目】
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。

现有一个链表 – head = [4,5,1,9],它可以表示为:

示例 1:*

输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.

示例 2:

输入: head = [4,5,1,9], node = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* insertionSortList(ListNode* head) {
        ListNode* dummyHead = new ListNode(0);
        if(head==NULL||head->next==NULL)
        return head;
        ListNode* cur = head->next;
        ListNode* pre = head;

        
        while(cur!=NULL)
        {
            ListNode* t=cur;
            ListNode* 
            if(cur->val<pre->)

        }
    }
};

12、删除链表的倒数第N个元素

Leetcode 19
【题目】
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:

给定的 n 保证是有效的。

进阶:

你能尝试使用一趟扫描实现吗?
用双指针,设立虚拟头结点,首先移动指针得到一个长度为n的窗口,然后滑动窗口。
在这里插入图片描述

在这里插入图片描述

上代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next=head;
        ListNode* p = dummyHead;
        ListNode* q = dummyHead;
        
        for(int i = 0 ; i< n+1 ; i ++ )
        {
            q = q ->next;
        }
        while(q!=NULL)
        {
            p=p->next;
            q=q->next;
        }
            
            ListNode* deleteNode = p->next;
            p->next=deleteNode->next;
            delete deleteNode;
            return dummyHead->next;
        
    }
};

13、旋转链表

Leetcode 61

【题目】
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

示例 1:

输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL

示例 2:

输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL

用的是双指针思想,先组成一个环,然后再把环拆开

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if(head==NULL||head->next==NULL)
        {
            return head;
        }
        int m=1;
        ListNode* p = head;
        ListNode* q = head;
        while(q->next!=NULL)
        {
            q=q->next;
            m++;
        }
        q->next=p;
        for(int i = 0 ; i<m-k%m ; i++)
        {
            q=q->next;
            p=p->next;
        }
        q->next=NULL;
        return p;
        
    }
};

14、重排链表

Leetcode 143
【题目】
给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

给定链表 1->2->3->4, 重新排列为 1->4->2->3.

示例 2:

给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.

我的做法是用了一个双端队列,一前一后提取数据。
上代码,是自己想的,还是挺开心的,就是占用内存比较多一点。是 O ( n ) O(n) O(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 {
public:
    void reorderList(ListNode* head) {
        deque<ListNode*> dq;
        ListNode*cur=head;
        int m=0;

        while(cur!=nullptr)
        {
            dq.push_back(cur);
            cur=cur->next;
            m++;
        }

        while(!dq.empty())
        {
            
            ListNode* top = dq.front();
            dq.pop_front();
            m--;
            ListNode* tail = dq.back();
            dq.pop_back();
            top->next=tail;
            m--;
            if(m>=2)
            {
                tail->next=dq.front(); 
            }
            else if(m==1)
            {
                tail->next=dq.front();
                dq.front()->next=nullptr;
                return;
            }
            else
            {
                tail->next=nullptr;
                return;
            }
        }
               
    }
};

还有递归和快慢指针的方法,快慢指针的方法看到两次了。
通过快慢指针可以得到链表中点的位置和判断链表内部是否存在循环。
参考思路
在这里插入图片描述

class Solution {
    public void reorderList(ListNode head) {
        if(head == null){
            return ;
        }
        //1. 使用快慢指针,找出链表的中心节点。
        // 1->2->3->4->5,中心节点为3
        ListNode middle = middleNode(head);

        //2. 将原始链表按照中心链表分割为两个链表,并将右链表反转
        //2.1 原始链表:1->2->3->4->5 左链表:1->2->3 右链表:4->5
        ListNode left = head;
        ListNode right = middle.next;
        middle.next = null;

        //2.2 反转右链表
        //原始右链表:4->5 反转后:5->4
        right = reverse(right);

        //3. 合并两个链表,将右链表插入到左链表
        //左链表:1->2->3 右链表:4->5 合并后:1->5->2->4->3
        merge(left,right);
    }

    //1. 使用快慢指针,找出链表的中心节点
    public ListNode middleNode(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;

        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }

    //2. 通过递归反转链表
    public ListNode reverse(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode last = reverse(head.next);
        head.next.next = head;
        head.next = null;
        return last;
    }

    //3. 合并两个链表,将右链表插入到左链表
    public void merge(ListNode left, ListNode right){
        ListNode leftTemp;
        ListNode rightTemp;
        while (left.next != null && right!= null) {
            //1. 保存next节点
            leftTemp = left.next;
            rightTemp = right.next;

            //2. 将右链表的第一个节点插入到左链表中
            // 左链表:1->2->3 右链表:5->4 
            // 合并后的左链表:1->5->2->3 
            left.next = right;
            right.next = leftTemp;

            //3. 移动left和right指针
            //左链表变为:2->3 右链表变为:4
            left = leftTemp;
            right = rightTemp;
        }
    }
}

这个递归的方法我倒是看懂了,递归要一块一块的去考虑

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    void reorderList(ListNode* head) {
        if (head == nullptr) {
            return;
        }
        ListNode* cur =head;
        int len = 0;
        while (cur) {
            len++;
            cur = cur->next;
        }
        helper(head, len);
    }

    ListNode* helper(ListNode* head, int len) {
        if (len == 1) {
            return head;
        } else if (len == 2) {
            return head->next;
        } else {
            // 每次需要减,因为去掉了头和尾两个节点
            ListNode* tail = helper(head->next, len-2);
            ListNode* th = head->next;
            head->next = tail->next;
            ListNode* tt = tail->next->next;
            tail->next->next = th;
            // tail其实不会变的,只是每次让它的next指向更外层的节点
            // 一顿操作之后把tail后面的都调整到前面,就结束了
            tail->next = tt;
            return tail;
        }
    }
};

作者:xiao-ge-40
链接:https://leetcode-cn.com/problems/reorder-list/solution/cdi-gui-jie-fa-by-xiao-ge-40/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

15、回文链表

Leetcode 234
【题目】
请判断一个链表是否为回文链表。

示例 1:

输入: 1->2
输出: false
示例 2:

输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

1、快慢链表找到链表的中点
2、反转后半部分链表
3、遍历链表判断是否是回文链表
4、反转链表,回到初始链表状况

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

    }
    ListNode* reverse(ListNode * node)
    {
        if(node==NULL||node->next==NULL)
            return node;
        ListNode * cur=node;
        ListNode * pre=NULL;
        while(cur!=NULL)
        {
            ListNode * n=cur->next;
            cur->next=pre;
            pre=cur;
            cur=n;
        }
        return pre;

    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值