0
点赞
收藏
分享

微信扫一扫

链表刷题集合

链表刷题集合

160. 相交链表

image-20210604085151993

image-20210604085208709

代码

/**

 * Definition for singly-linked list.

 * struct ListNode {

 * int val;

 * struct ListNode *next;

 * };
   */
    //思路:1.找到两个链表中较大的那一个,然后让长链表先走他们的差距部,等到他们位于同一起点,然后两者
    //       一起走,直到两者到达同一节点处和
    //特殊情况的处理:
    //1.两个链表的只想都为null,返回true,两个链表中只有一个指向为null,返回false
   struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
   //1.两个头指针都为null
   if(headA==NULL&&headB==NULL)
   {
       return headA;
   }
   //2.两个结点其中一个为空
   if(headA==NULL||headB==NULL)
   {
       return NULL;
   }

   //3.排除特殊情况之后,我们就要开始处理正常情况
   int LenA=0,LenB=0;
   struct ListNode*curA=headA;
   struct ListNode*curB=headB;
   while(curA!=NULL)
   {
       LenA++;
       curA=curA->next;
   }
   while(curB!=NULL)
   {
        LenB++;
        curB=curB->next;
    }
    int n=abs(LenA-LenB);
    if(LenA>LenB)
    {
        while(n--)
        {
            headA=headA->next;
        }
    }
    else
    {
        while(n--)
        {
            headB=headB->next;
        }
    }
    curA=headA;
    curB=headB;
    while(curA!=NULL&&curB!=NULL)
    {
        if(curA==curB)
        {
            return curA;
        }
        curA=curA->next;
        curB=curB->next;
    }
    return NULL;
}

203. 移除链表元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点

image-20210605094030306

实例1:
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
实例2:
输入:head = [], val = 1
输出:[]
实例3:
输入:head = [7,7,7,7], val = 7
输出:[]
**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* removeElements(struct ListNode* head, int val){
    //创建一个哨兵位的头节点
    struct ListNode*pHead=(struct ListNode*)malloc(sizeof(struct ListNode));
    //连接头节点和这个链表的元素
    pHead->next=head;
    //cur指向现在的头节点
    struct ListNode*cur=pHead;
    //prev作为前驱指针
    struct ListNode*prev=NULL;
    while(cur!=NULL)
    {
    //如果cur->val==val,执行删除操作,其中prev指向前驱指针,Next指向要删除元素的下一个地方
        if(cur->val==val)
        {
            struct ListNode*Next=cur->next;
            prev->next=Next;
            free(cur);
            cur=Next;
        }
        else
        {
        此时prev总是比cur少一个
            prev=cur;
            cur=cur->next;
        }
    }
    return pHead->next;
}
/** * Definition for singly-linked list. 
* struct ListNode { 
*     int val;
*     struct ListNode *next; 
* }; 
*/  
struct ListNode* removeElements(struct ListNode* head, int val){ 
    //本题特殊情况:当头结点为val时
   struct ListNode*cur=head;
   struct ListNode*prev=NULL;
   while(cur!=NULL)
   { 
        struct ListNode*next=cur->next;
        if(cur->val==val)
        { 
         //当第一个节点为val时,代表prev为空,那我们直接释放这个节点,然后让head指针指向下一个元素 
         //然后让将下一个节点赋给cur
             if(prev==NULL)
             { 
                 head=next;
                 free(cur);
                 cur=next;
             } 
        //当第一个节点不为空时,我们使prev直接指向cur的下一个元素,释放cur,将next赋给cur
             else
             {
                prev->next=next;
                free(cur); 
                cur=next;
            } 
        } 
        //如果该节点不是val,那么将cur赋给prev,然后cur指向下一个元素
        else 
        {
            prev=cur; 
            cur=cur->next; 
        } 
    } 
    return head;

剑指 Offer II 024. 反转链表

image-20210910202551951

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

image-20210910202615885

输入:head = [1,2]
输出:[2,1]
输入:head = []
输出:[]
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        //判断头结点是否为空
        if(head==nullptr)
        return nullptr;
        ListNode*cur=head;
        //创建新的头结点
        ListNode*NewHead=nullptr;
        while(cur)
        {
            ListNode*next=cur->next;
            //使当前节点的下一个元素指向新的头结点
            cur->next=NewHead;
            //使得cur成为新的头节点
            NewHead=cur;
            cur=next;
        }
        return NewHead;
    }
};

148. 排序链表

image-20210911105926649

输入:head = [4,2,1,3]
输出:[1,2,3,4]

image-20210911105945165

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
输入:head = []
输出:[]
class Solution {
public:
//链表的排序:归并排序
//1.找到中间节点
//2.将链表分为两部分
//3.实现有序链表的排序
    ListNode*Sort(ListNode*&l,ListNode*&r)
    {
    //到这里就是排序的思想了,排序思想和合并两个有序链表的思想差不多
    //创建新的节点,然后按照插入排序的思想,谁大谁就插入
        ListNode*dummyHead=new ListNode(0);
        ListNode*cur=dummyHead;
        while(l!=nullptr&&r!=nullptr)
        {
            if(l->val<=r->val)
            {
                cur->next=l;
                cur=cur->next;
                l=l->next;
            }
            else
            {
                cur->next=r;
                cur=cur->next;
                r=r->next;
            }
        }
        if(l!=nullptr)
        {
            cur->next=l;
        }
        if(r!=nullptr)
        {
            cur->next=r;
        }
        return dummyHead->next;
    }
    //传递参数时记得引用传递
    ListNode*MergSort(ListNode*&head)
    {
    //判断头节点的下一个节点是否为空,如果是,直接返回头节点
        if(head->next==nullptr)
        return head;
        //定义快慢指针,寻找中间节点
        ListNode*slow=head;
        ListNode*fast=head;
        ListNode*prev=nullptr;
        while(fast&&fast->next)
        {
            prev=slow;
            slow=slow->next;
            fast=fast->next->next;
        }
        //此时slow所在的位置就是中间节点所在的位置,prev指向slow的前一个节点
        //我们人为的让链表从slow这个地方断开,head->prev是链表的前半段,slow到完是链表的右半部分
        prev->next=nullptr;
		//递归在左、右两端继续找中间节点
        ListNode*l=MergSort(head);
        ListNode*r=MergSort(slow);
        //当分割的不能分割时,进行排序,最开始两两排序,到后来四四排序
        return Sort(l,r);
    }
    ListNode* sortList(ListNode* head) {
    //1.判断节点是否为空
        if(head==nullptr)
        return head;
        //2.进入归并排序,寻找中间节点
        return MergSort(head);

    }
};

725. 分隔链表

给你一个头结点为 head 的单链表和一个整数 k ,请你设计一个算法将链表分隔为 k 个连续的部分。

每部分的长度应该尽可能的相等:任意两部分的长度差距不能超过 1 。这可能会导致有些部分为 null 。

这 k 个部分应该按照在链表中出现的顺序排列,并且排在前面的部分的长度应该大于或等于排在后面的长度。

返回一个由上述 k 部分组成的数组。

image-20210922125123390

输入:head = [1,2,3], k = 5
输出:[[1],[2],[3],[],[]]
解释:
第一个元素 output[0] 为 output[0].val = 1 ,output[0].next = null 。
最后一个元素 output[4] 为 null ,但它作为 ListNode 的字符串表示是 []

image-20210922125838800

输入:head = [1,2,3,4,5,6,7,8,9,10], k = 3
输出:[[1,2,3,4],[5,6,7],[8,9,10]]
解释:
输入被分成了几个连续的部分,并且每部分的长度相差不超过 1 。前面部分的长度大于等于后面部分的长度。

思路:

1.求链表得节点个数

2.如果节点个数<K,说明节点个数不够分割,那么就让前面几个节点单独为一个,后面的都为NULL,凑齐k个

3.链表节点>K并且有剩余,那么我们就k个节点为一组,如果有剩余,那么剩余的节点每次多添加一个给前面的节点

class Solution {
public:
    vector<ListNode*> splitListToParts(ListNode* head, int k) {
        vector<ListNode*>ret;
        //首先遍历得到链表的长度
        //每k个一组进行分割,分别进入链表
        ListNode*cur=head;
        int sum=0;
        while(cur)
        {
            sum++;
            cur=cur->next;
        }
        int temp=sum/k;//判断每组有多少个节点
        cur=head;
        //temp==0说明链表节点少于K个,那么就将链表单独分割,不足的用nullptr代替
        if(temp==0)
        {
            //此时说明k>sum,说明不够分
            while(k--)
            {
                if(cur)
                {
                    ListNode*next=cur->next;
                    cur->next=nullptr;
                    ret.push_back(cur);
                    cur=next;
                }
                else
                {
                    ret.push_back(nullptr);
                }
            }
            return ret;
        }
		//让cur重新指向头
        cur=head;
        //next用来记录cur得下一个位置
        ListNode*next=cur->next;
        //phead指向cur的起始位置,以便于后续将该节点加入到数组中
        ListNode*phead=cur;
        //判断有没有余数,如果有余数则一次让前面几个组的temp值+1
        int remind=sum%k;
        //k用来控制外层循环,即用来表示要分的组数
        while(k--)
        {
        //里面即表示每组的成员
            int val=temp;
            if(remind!=0)
            val+=1;
            //从cur位置开始往后走val步即到达每个组的数量
            while(--val)
            {
                cur=cur->next;
            }
            next=cur->next;
            if(cur!=nullptr)
            cur->next=nullptr;
            //入数组
            ret.push_back(phead);
            //重新使cur指向下一个位置
            cur=next;
            //phead重新指向cur的起始位置
            phead=cur;
            //余数--
            if(remind)
            remind--;
        }

        return ret;


    }
};

430. 扁平化多级双向链表

思路:将该图旋转一下,发现它非常像一颗二叉树,child相当于左孩子,next相当于右孩子,那么我们只要前序遍历这颗二叉树,就能得到正确答案

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* prev;
    Node* next;
    Node* child;
};
*/

class Solution {
public:
//创建全局变量,设置一个哨兵位置的头节点
      Node*dummy=new Node();
        Node*p=dummy;
    void dfs(Node*&head)
    {
    //将head连接到p->next
        p->next=new Node();
        p->next->val=head->val;
        p->next->prev=p;
        p=p->next;
        //递归遍历左子树
        if(head->child)
        {
            dfs(head->child);
        }
//递归遍历右子树
        if(head->next)
        {
            dfs(head->next);
        }
        
    
    }
    Node* flatten(Node* head) {
    //判断头节点是否为空
        if(head==nullptr)
        return nullptr;

        dfs(head);
        //将最后一个节点的下一个位置置为nullptr
        p->next=nullptr;
        //将第一个节点与前面哨兵位置断开
       dummy->next->prev=nullptr;

        return dummy->next;
        
    }
};

删除有序链表中重复的元素-I

删除给出链表中的重复元素(链表中元素从小到大有序),使链表中的所有元素都只出现一次
例如:
给出的链表为1->1->-2,返回1->2.
给出的链表为1->1->2->3->3,返回1→2→3.

数据范围:链表长度满足 0 \le n \le 1000≤n≤100,链表中任意节点的值满足 |val| \le 100∣val∣≤100
进阶:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)
输入:
{1,1,2}
复制
返回值:
{1,2}

​ 代码如下所示

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 */

class Solution {
public:
    /**
     * 
     * @param head ListNode类 
     * @return ListNode类
     */
    ListNode* deleteDuplicates(ListNode* head) {
        // write code here
        if(head==nullptr||head->next==nullptr)
        {
            return head;
        }
        ListNode*cur=head;
        while(cur&&cur->next)
        {
            ListNode*next=cur->next;
            //前后双指针进行判断
            if(cur->val==next->val)
            {
                cur->next=next->next;
                delete next;
            }
            else
            {
                cur=cur->next;
            }
        }
        return head;
    }
};

删除有序链表中重复的元素-II

给出一个升序排序的链表,删除链表中的所有重复出现的元素,只保留原链表中只出现一次的元素。
例如:
给出的链表为1233445, 返回125.
给出的链表为11123, 返回23.

数据范围:链表长度 0 \le n \le 100000*n*10000,链表中的值满足 |val| \le 1000*v**a**l*∣≤1000

要求:空间复杂度 O(n)*O*(*n*),时间复杂度 O(n)*O*(*n*)

进阶:空间复杂度 O(1)*O*(1),时间复杂度 O(n)*O*(*n*)
示例1
输入:
{1,2,2}
复制
返回值:
{1}

代码示例

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 */

class Solution {
public:
    /**
     * 
     * @param head ListNode类 
     * @return ListNode类
     */
    ListNode* deleteDuplicates(ListNode* head) {
    
     	 // write code here
        //哈希映射,判断是否有重复值
        //文中题目结点的val范围为|val|<=1000
        //也就是-1000<=val<=1000
        //我们人为映射统计每个节点出现的次数,然后判断是不是只出现了一次
        //我们可以创建一个大小为2000的数组,为什么是2000呢,因为数组范围-1000,1000
        //我们无法直接映射负数到数组中,每次让val+1000即可
        //即-1000+1000<=val+1000<=1000+1000;
        //一次遍历映射,判断是否出现一次,这样也符合题目要求的时间复杂度为O(N),空间负责都为O(1)
        // write code here
        //哈希映射,判断是否有重复值
        int*arr=new int[2000]; 
        ListNode*cur=head;
        while(cur)
        {
            arr[cur->val+1000]++;
            cur=cur->next;
        }
        cur=head;
        
        //建立头结点
        ListNode*NewHead=new ListNode(0);
        ListNode*tail=NewHead;
        while(cur)
        {
            if(arr[cur->val+1000]==1)
            {
                tail->next=cur;
                tail=tail->next;
            }
            cur=cur->next;
        }
        tail->next=nullptr;
        return NewHead->next;
    }
};
  //我们无法直接映射负数到数组中,每次让val+1000即可
    //即-1000+1000<=val+1000<=1000+1000;
    //一次遍历映射,判断是否出现一次,这样也符合题目要求的时间复杂度为O(N),空间负责都为O(1)
    // write code here
    //哈希映射,判断是否有重复值
    int*arr=new int[2000]; 
    ListNode*cur=head;
    while(cur)
    {
        arr[cur->val+1000]++;
        cur=cur->next;
    }
    cur=head;
    
    //建立头结点
    ListNode*NewHead=new ListNode(0);
    ListNode*tail=NewHead;
    while(cur)
    {
        if(arr[cur->val+1000]==1)
        {
            tail->next=cur;
            tail=tail->next;
        }
        cur=cur->next;
    }
    tail->next=nullptr;
    return NewHead->next;
}

};


举报

相关推荐

LeetCode刷题 --- 链表

链表刷题总结

链表刷题——20220404

C++刷题 -- 链表

链表必刷题一

【LeetCode】单链表——刷题

算法刷题之链表

0 条评论