学习笔记—数据结构—单链表(练习题)

目录

前言:

一、移除链表元素

1.1思路

1.2代码实现

二、反转链表

1.1思路

1.2代码实现

三、链表的中间结点

1.1思路

1.2代码实现

四、合并两个有序链表

1.1思路

1.2代码实现

五、链表分割

1.1思路

1.2代码实现

六、链表的回文结构

1.1思路

1.2代码实现

七、相交链表

1.1思路

1.2代码实现

八、环形链表I

1.1思路

1.2代码实现

九、环形链表II

1.1思路

1.2代码实现


前面介绍了单链表(无头单向非循环链表)结构和操作,那么我们该如何好好利用所学的知识解决问题呢,光说不练假把式,接下来让我们破解一些练习题吧!

前言:

对于咱们对编程有兴趣或者成为陌生手段来说,刷题一般用牛客网和力扣

⽜客⽹:牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网

力扣:力扣 (LeetCode) 全球极客挚爱的技术成长平台

一、移除链表元素

203. 移除链表元素 - 力扣(LeetCode)

1.1思路

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

创建一个新链表(newTail,newHead)置为空,创建一个指针pcur指向头节点head。

开始遍历pcur不为空,判断如果pcur的值不等于val:

如果newHead为空,新链表等于pcur;

不为空则newTail下一个节点等于pcur,newTail下移一个节点。

pcur下移

如果newTail不为空,则newTail下一个节点为空

返回newHead。

1.2代码实现

typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {
    //创建新链表
    ListNode* newHead,*newTail;
    newHead = newTail = NULL;
    //遍历原链表
    ListNode* pcur = head;
    while(pcur)
    {
        //找值不为val的节点,往新链表中进行尾插
        if(pcur->val != val)
        {
            //链表为空
            if(newHead == NULL)
            {
                newHead = newTail = pcur;
            }
            //链表不为空
            else
            {
                newTail->next = pcur;
                newTail = newTail->next;
            }
        }
        pcur=pcur->next;
    }
    if(newTail)
        newTail->next=NULL;
    return newHead;    
}

二、反转链表

206. 反转链表 - 力扣(LeetCode)

1.1思路

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

判断head如果为空,则返回head。

创建三个指针n1=NULL,n2=head,n3=n2->next。

遍历n2不为空:n2->next=n1,n1=n2,n2=n3。

判断n3不为空,n3=n3->next。

最后返回n1。

1.2代码实现

typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {
    //处理空链表
    if(head == NULL)
    {
        return head;
    }
    //创建三个指针
    ListNode* n1,*n2,*n3;
    n1=NULL,n2=head,n3=n2->next;
    while(n2)
    {
        n2->next=n1;
        n1=n2;
        n2=n3;
        if(n3)
            n3=n3->next;
    }
    //此时n1就是链表反转后的新的头结点
    return n1;  
}

三、链表的中间结点

876. 链表的中间结点 - 力扣(LeetCode)

1.1思路

给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

使用快慢指针,创建2个指针slow , fast。

slow走一格,fast走两格。

当fast==NULL&&fast->==NULL时slow正好在中间。

返回slow。

1.2代码实现

typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
    //创建慢指针slow,慢指针fast
    ListNode*slow=head,*fast=head;
    //慢指针走一步,快指针走两步
    while(fast && fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
    }
    //此时slow正好在中间
    return slow;
}

四、合并两个有序链表

21. 合并两个有序链表 - 力扣(LeetCode)

1.1思路

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

当list1或list2有一个为空时,直接返回另一个

创立一个新链表,创立两个头指针l1=list1,l2=list2,

创建两个空指针newHead和newTail指向为空。

l1和l2比大小,小的进newTali,然后newTail向下移动一格节点

最后比完大小如果l1没了l2剩一个,那么newTali的下一个节点就是l2,反之

1.2代码实现

typedef struct ListNode ListNode; 
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
   //处理链表为空情况
    if(list1 == NULL)
    {
        return list2;
    }
    if(list2 == NULL)
    {
        return list1;
    }
    //创建一个新链表newHead,newTail
    ListNode*newHead=NULL,*newTail=NULL;
    //创立两个指针l1,l2分别指向两个链表的头节点
    ListNode*l1=list1,*l2=list2;
    while(l1 && l2)
    {
        if(l1->val < l2->val)
        {
            //l1插入新链表
            if(newHead == NULL)
            {
                newHead=newTail=l1;
            }
            else
            {
                newTail->next=l1;
                newTail=newTail->next;
            }
            l1=l1->next;
        }
        else
        {
            //l2插入新指针
            if(newHead == NULL)
            {
                newHead=newTail=l2;
            }
            else
            {
                newTail->next=l2;
                newTail=newTail->next;
            }
            l2=l2->next;
        }
    }
    //跳出循环只有两种情况:要么l1为空(l2不为空),要么l2为空(l1不为空)
    if(l1)
    {
        newTail->next=l1;
    }
    if(l2)
    {
        newTail->next=l2;
    }
    return newHead;
}

五、链表分割

链表分割_牛客题霸_牛客网

1.1思路

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

创建一个头指针pcur存储pHead;创建俩个非空链表,小节点less,大节点Great.

<X存入less反之;大节点尾GreatTail->NULL.

合并两个链表,释放两个链表的头节点,创建一个指针ret储存结果链表的头lessHead.

返回ret.

1.2代码实现

#include <cstddef>
#include <cstdlib>
class Partition {
  public:
    ListNode* partition(ListNode* pHead, int x) {
        // write code here
        //创建俩个非空链表
        ListNode* lessHead, *lessTail;
        lessHead = lessTail = (ListNode*)malloc(sizeof(ListNode));
        ListNode* GreatHead, *GreatTail;
        GreatHead = GreatTail = (ListNode*)malloc(sizeof(ListNode));
        //创建一个头指针
        ListNode* pcur = pHead;
        while (pcur) {
            if (pcur->val < x) {
                lessTail->next = pcur;
                lessTail = lessTail->next;
            } else {
                GreatTail->next = pcur;
                GreatTail = GreatTail->next;
            }
            pcur = pcur->next;

        }
        GreatTail->next = NULL;
        //合并链表
        lessTail->next = GreatHead->next;
        //创建一个新链表
        ListNode* ret = lessHead->next;
        free(lessHead);
        free(GreatHead);
        lessHead = GreatHead = NULL;
        return ret;
    }

    
};

六、链表的回文结构

链表的回文结构_牛客题霸_牛客网

1.1思路

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900

1.2代码实现

class PalindromeList {
public:
    ListNode*findMidNode(ListNode*phead)
    {
        ListNode*slow=phead;
        ListNode*fast=phead;
        while (fast && fast->next) 
        {
            slow=slow->next;
            fast=fast->next->next;
        }
        return slow;
    }
    ListNode*reverseList(ListNode*phead)
    {
        ListNode*n1,*n2,*n3;
        n1=NULL,n2=phead,n3=n2->next;
        while (n2) 
        {
            n2->next=n1;
            n1=n2;
            n2=n3;
            if(n3)
            {
                n3=n3->next;
            }
        }
        return n1;
    }
    bool chkPalindrome(ListNode* A) 
    {
        // write code here
        ListNode*mid=findMidNode(A);
        ListNode*right=reverseList(mid);
        ListNode*left=A;
        while (right) 
        {
            if (left->val != right->val) 
            {
                return false;
            }
            left=left->next;
            right=right->next;
        }
        return true;
    }
};

七、相交链表

160. 相交链表 - 力扣(LeetCode)

1.1思路

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

1.2代码实现

 typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    ListNode* l1 = headA;
    ListNode* l2 = headB;
    int sizeA=0,sizeB=0;
    while(l1)
    {
        sizeA++;
        l1=l1->next;
    }
     while(l2)
    {
        sizeB++;
        l2=l2->next;
    }
    //求绝对值
    int gap =abs(sizeA-sizeB);

    //让长链表先走gap步
    ListNode*longList = headA;
    ListNode*shortList = headB;
    if(sizeA < sizeB)
    {
        longList = headB;
        shortList = headA;
    }
    while(gap--)
    {
        longList = longList->next;
    }
    //此时longList和shortList指针在同一起跑线
    while(longList && shortList)
    {
        if(longList == shortList)
        {
            //链表相交
            return longList;
        }
        //继续往后走
        longList = longList->next;
        shortList = shortList->next;

    }
    //链表不相交
    return NULL;
}

八、环形链表I

141. 环形链表 - 力扣(LeetCode)

1.1思路

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

1.2代码实现

 typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) 
{
    //快慢指针
    ListNode*slow = head;
    ListNode*fast = head;
    while(fast && fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow == fast)
        {
            return true;
        }
        
    }
    //两个指针没有相遇
    return false;
}

九、环形链表II

142. 环形链表 II - 力扣(LeetCode)

1.1思路

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

创建快慢节点slow,fast

当两节点相遇时,创建一个头指针pcur,

如果相遇点slow没有和pcur相等,则都下走一个节点

相遇返回pcur

1.2代码实现

 typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) 
{
    ListNode*slow=head;
    ListNode*fast=head;
    while(fast && fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow == fast)
        {
            ListNode*pcur=head;
            while(pcur != slow)
            {
                pcur=pcur->next;
                slow=slow->next;
            }
            return pcur;
        }
    }
    return NULL;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值