链表练习题

一、移除链表元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
在这里插入图片描述
提示:

列表中的节点数目在范围 [0, 104] 内
1 <= Node.val <= 50
0 <= val <= 50


```c
struct ListNode* removeElements(struct ListNode* head, int val){
        struct ListNode* cur=head;
        struct ListNode* pre=NULL;
        
        while(cur)
        {
            if(cur->val==val)
            {
                 if(cur==head)
                 {
                //cur为第一个节点,采用头删
                    head=cur->next;
                    free(cur);
                    cur=head;
                }
                else{
                    //cur不是第一个节点
                    pre->next=cur->next;
                    free(cur);
                    cur=pre->next;
                }
            }
            else
            {
                pre=cur;
                cur=cur->next;
            }
           
        }
        return head;
}

二、链表的中间结点


给定一个头结点为 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

示例 1:

输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5]) 返回的结点值为 3 。(测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样: ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
示例 2:
输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6]) 由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。

提示:

给定链表的结点数介于 1 和 100 之间。

//给出两个指针,一个fast一个slow,fast走两步,slow走一步,当fast走到头的时候,slow刚到中间位置,则直接返回slow
struct ListNode* middleNode(struct ListNode* head){
    struct ListNode* fast=head;
    struct ListNode* slow=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
    }
    return slow;
}

三、反转链表


给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:
在这里插入图片描述

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例 2:
在这里插入图片描述

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

输入:head = []
输出:[]

提示:

链表中节点的数目范围是 [0, 5000]
-5000 <= Node.val <= 5000

typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head){
    ListNode* cur=head;//指向头结点
    ListNode* pre=NULL;//用来记录插入之后最后一个节点
    ListNode* next=NULL;//用来记录cur的前一个节点

    while(cur)
    {
        next=cur->next;//先将cur的下一个节点保存在next
        cur->next=pre;//将节点插入到pre中
        pre=cur;
        cur=next;
    }
    return pre;
}

四、链表中倒数第k个结点

描述 输入一个链表,输出该链表中倒数第k个结点
示例1
输入: 1,{1,2,3,4,5}
返回值: {5}

//让fast先向后走K步
//再让slow与fast同时往后移动,直到fast走到链表的末尾,slow所指向的节点则为倒数第K个节点
typedef struct ListNode ListNode;
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    // write code here
    if(NULL==pListHead||k==0)
    {
        return NULL;
    }
    ListNode* fast=pListHead;
    ListNode* slow=pListHead;
    while(k--){
        if(NULL==fast)
            return NULL;
        fast=fast->next;
    }
    while(fast)
    {
        fast=fast->next;
        slow=slow->next;
    }
    return slow;
}

五、合并两个有序链表


将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
在这里插入图片描述

提示:
两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
11 和 12 均按非递减顺序排列

typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    if(l1==NULL)
    {
        return l2;
    }
    if(NULL==l2)
    {
        return l1;
    }
    //两个链表都不为空
    
    ListNode* cur1=l1;
    ListNode* cur2=l2;
    ListNode new; 
    ListNode* tailNode=&new;
    while(cur1&&cur2)
    {
        if(cur1->val<=cur2->val)
        {
            tailNode->next=cur1;
            cur1=cur1->next;
        }
        else{
            tailNode->next=cur2;
            cur2=cur2->next;
        }
        tailNode=tailNode->next;
    }
    if(cur1)
        tailNode->next=cur1;
    else
        tailNode->next=cur2;

    return new.next;
}

六、复制带随机指针的链表

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。 返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。 你的代码 只 接受原链表的头节点 head 作为传入参数。

示例1:在这里插入图片描述
在这里插入图片描述
示例 3:

输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。

提示:

0 <= n <= 1000
-10000 <= Node.val <= 10000 Node.random 为空(null)或指向链表中的节点。


typedef struct Node Node;
Node* BuyRandomListNode(int val)
{
    Node* newNode=(Node*)malloc(sizeof(Node));
    if(NULL==newNode)
        return NULL;
    newNode->val=val;
    newNode->next=NULL;
    newNode->random=NULL;

    return newNode;
}
struct Node* copyRandomList(struct Node* head) {
	if(NULL==head)
        return NULL;
    Node* newNode=NULL;
    //1、在原链表中每个节点后添加相等的新节点
    Node* cur=head;
    while(cur)
    {
        newNode=BuyRandomListNode(cur->val);
        if(NULL==newNode)
        {
            return NULL;
        }
        newNode->next=cur->next;
        cur->next=newNode;
        cur=newNode->next;
    }

    //2.给新插入节点的随机指针域进行赋值
    cur=head;
    while(cur)
    {
        newNode=cur->next;
        if(cur->random)
        {
            newNode->random=cur->random->next; 
        }
        cur=newNode->next;

    }
    //3、将新插入的节点从原链表中拆下来
    Node* newHead=head->next;
    cur=head;
    while(cur->next)
    {
        newNode=cur->next;
        cur->next=newNode->next;
        cur=newNode;
    }

    return newHead;
}

七、排序链表删除重复节点

描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。
例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
示例1 输入: {1,2,3,3,4,4,5}
返回值:{1,2,5}

class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead) {
        ListNode* start=pHead;
        ListNode* end=start;
        ListNode* pre=NULL;
        
        while(start)
        {
            end=start->next;
            //找重复节点的范围
            while(end)
            {
                if(start->val!=end->val)
                {
                    break;
                }
                end=end->next;
            }
            //[start,end]区间的节点删除
            if(start->next==end)
            {
                //区间中没有重复的节点
                pre=start;
                start=end;
            }
            else{
                //有重复的节点
                while(start!=end)
                {
                    //头删
                    if(start==pHead)
                    {
                        pHead=start->next;
                        free(start);
                        start=pHead;
                    }
                    else
                    {
                        pre->next=start->next;
                        free(start);
                        start=pre->next;
                    }
                }
            }
        }
        return pHead;
    }
}; 
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值