链表——精选题目

「C++ 40 周年」主题征文大赛(有机会与C++之父现场交流!) 10w+人浏览 464人参与

目录

1.移除链表元素

思路:创建新链表

2.反转链表

思路一:创建新链表头插

思路二:创建三个指针,改变链表中指针的方向

3.链表的中间结点

思路一:先求链表总长度,然后长度除以2得到中间位置,再遍历找到中间节点。

思路二:快慢指针

4.合并两个有序链表

思路:创建新链表,比较两个原链表,谁小谁尾插

5.链表分割

思路:新建两个连表,分别放 =x的值,再将两个链表相连

6.链表的回文结构

思路一:创建新链表,将原链表头插,对比两个链表是否相同

思路二:创建数组法

思路三:找链表中间节点,以其为新链表的头节点,反转新链表,遍历与原链表比较

7.相交链表

思路:求两个链表的长度,让长链表先走长度差,让后长短链表同步遍历找相同节点

8.环形链表1

思路:利用快慢指针,若快慢指针相遇,则链表有环

9.环形链表2

思路:用快慢指针找到相遇节点,利用“相遇节点到头节点的距离==头节点到入环节点的距离”求出入环节点

1.移除链表元素

题目链接:

203. 移除链表元素 - 力扣(LeetCode)https://leetcode.cn/problems/remove-linked-list-elements/description/题目描述:

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

思路:创建新链表

struct ListNode* removeElements(struct ListNode* head, int val) {
    struct ListNode* newhead = (struct ListNode*)malloc(sizeof(struct ListNode));
    newhead->next=NULL;
    struct ListNode* newtail=newhead;
    struct ListNode* pcur=head;
    while(pcur!=NULL)
    {
        if((pcur->val)!=val)
        {
            newtail->next=pcur;
            newtail=newtail->next;
        }
        pcur=pcur->next;
    }
    newtail->next=NULL;
    return newhead->next;
}

2.反转链表

题目链接:

206. 反转链表 - 力扣(LeetCode)https://leetcode.cn/problems/reverse-linked-list/description/题目简述:

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

思路一:创建新链表头插

struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode* newhead=NULL;
    struct ListNode* next=NULL;
    while(head)
    {
        next=head->next;    //一定要保存下一个节点的位置
        head->next=newhead; //不然这步将下一个节点销毁了
        newhead=head;
        head=next;
    }
    return newhead;
}

思路二:创建三个指针,改变链表中指针的方向

struct ListNode* reverseList(struct ListNode* head) {
    if(head==NULL)
    {
        return head;
    }
    struct ListNode* n1=NULL,*n2=head,*n3=n2->next;
    while(n2)
    {
        n2->next=n1;
        n1=n2;
        n2=n3;
        if(n3)
            n3=n3->next;
    }
    return n1;
}

3.链表的中间结点

题目链接:
876. 链表的中间结点 - 力扣(LeetCode)https://leetcode.cn/problems/middle-of-the-linked-list/description/题目简述:

给你单链表的头结点 head ,请你找出并返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

思路一:先求链表总长度,然后长度除以2得到中间位置,再遍历找到中间节点。

struct ListNode* middleNode(struct ListNode* head) {
    int len=0;
    struct ListNode* p=head;
    while(head)
    {
        head=head->next;
        len++;
    }
    int mid=len/2;
    while(mid)
    {
        p=p->next;
        mid--;
    }
    return p;
}

思路二:快慢指针

struct ListNode* middleNode(struct ListNode* head) {
    struct ListNode* fast=head;
    struct ListNode* slow=head;
    while(fast && fast->next)//绝对不可以写成fast->next && fast
    {
        fast=fast->next->next;
        slow=slow->next;
    }
    return slow;
}

4.合并两个有序链表

题目链接:

21. 合并两个有序链表 - 力扣(LeetCode)https://leetcode.cn/problems/merge-two-sorted-lists/description/题目描述:

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

思路:创建新链表,比较两个原链表,谁小谁尾插

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    struct ListNode* newnode=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* newhead=newnode;
    newnode->next=NULL;
    while(list1 && list2)
    {
        if(list1->val < list2->val)
        {
            newnode->next=list1;
            list1=list1->next;
        }
        else {
            newnode->next=list2;
            list2=list2->next;
        }
        newnode=newnode->next;
    }
    if(list1!=NULL)
    {
        newnode->next=list1;
    }
    if(list2!=NULL)
    {
        newnode->next=list2;
    }
    return newhead->next;
}

5.链表分割

题目链接:

链表分割_牛客题霸_牛客网https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70题目描述:

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

思路:新建两个连表,分别放<x和>=x的值,再将两个链表相连

ListNode* partition(ListNode* pHead, int x) {
        ListNode* lessHead,*lessTail;
        lessHead=lessTail=(ListNode*)malloc(sizeof(ListNode));
        ListNode* greaterHead,*greaterTail;
        greaterHead=greaterTail=(ListNode*)malloc(sizeof(ListNode));
        while(pHead)
        {
            if(pHead->val<x)
            {
                lessTail->next=pHead;
                lessTail=lessTail->next;
            }
            else {
                greaterTail->next=pHead;
                greaterTail=greaterTail->next;
            }
            pHead=pHead->next;
        }
        greaterTail->next=NULL;
        lessTail->next=greaterHead->next;
        return lessHead->next;
    }

6.链表的回文结构

题目链接:

链表的回文结构_牛客题霸_牛客网https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa题目描述:

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。

给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

思路一:创建新链表,将原链表头插,对比两个链表是否相同

#include <cstdio>
#include <cstdlib>
class PalindromeList {
  public:
    bool chkPalindrome(ListNode* A) {
        ListNode* cur = A;
        ListNode* newA = NULL;
        while (cur) {
            ListNode* node = (ListNode*)malloc(sizeof(ListNode));
            node->val=cur->val;
            node->next=NULL;
            if(newA==NULL) {
                newA=node;
            }
            else {
                node->next=newA;
                newA=node;
            }
            cur=cur->next;
        }
        while(A)
        {
            if(A->val!=newA->val)
            {
                return false;
            }
            A=A->next;
            newA=newA->next;
        }
        return true;  
    }
};

思路二:创建数组法


#include <cstdio>
#include <cstdlib>
class PalindromeList {
  public:
    bool chkPalindrome(ListNode* A) {
        int arr[900] = {0};
        int i = 0;
        while (A) {
            arr[i++] = A->val;
            A = A->next;
        }
        int left = 0;
        int right = i - 1;
        while (left < right) {
            if (arr[left] != arr[right]) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
};

思路三:找链表中间节点,以其为新链表的头节点,反转新链表,遍历与原链表比较

#include <cstdio>
#include <cstdlib>
class PalindromeList {
  public:
    ListNode* middleNode(ListNode* head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while (fast && fast->next) { //绝对不可以写成fast->next && fast
            fast = fast->next->next;
            slow = slow->next;
        }
        return slow;
    }
    ListNode* reverseList(ListNode* head) {
        if (head == NULL) {
            return head;
        }
        ListNode* n1 = NULL, *n2 = head, *n3 = n2->next;
        while (n2) {
            n2->next = n1;
            n1 = n2;
            n2 = n3;
            if (n3)
                n3 = n3->next;
        }
        return n1;
    }
    bool chkPalindrome(ListNode* A) {
        //找中间节点
        ListNode* mid=middleNode(A);
        //反转新链表
        ListNode* right=reverseList(mid);
        //遍历比较
        ListNode* left=A;
        while(right)
        {
            if(right->val!=left->val)
            {
                return false;
            }
            right=right->next;
            left=left->next;
        }
        return true;
    }
};

7.相交链表

题目链接:

160. 相交链表 - 力扣(LeetCode)https://leetcode.cn/problems/intersection-of-two-linked-lists/description/题目描述:

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

思路:求两个链表的长度,让长链表先走长度差,让后长短链表同步遍历找相同节点

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    int la=0,lb=0;
    struct ListNode *pa=headA;
    struct ListNode *pb=headB;
    while(pa)
    {
        la++;
        pa=pa->next;
    }
    while(pb)
    {
        lb++;
        pb=pb->next;
    }
    int gap=abs(la-lb);
    struct ListNode *longlist=headA;
    struct ListNode *shortlist=headB;
    if(la<lb)
    {
        longlist=headB;
        shortlist=headA;
    }
    while(gap--)
    {
        longlist=longlist->next;
    }
    while(shortlist)
    {
        if(shortlist==longlist)
        {
            return shortlist;
        }
        shortlist=shortlist->next;
        longlist=longlist->next;
    }
    return NULL;
}

8.环形链表1

题目链接:

141. 环形链表 - 力扣(LeetCode)https://leetcode.cn/problems/linked-list-cycle/description/题目描述:

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

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

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

思路:利用快慢指针,若快慢指针相遇,则链表有环

bool hasCycle(struct ListNode *head) {
    struct ListNode *fast=head;
    struct ListNode *slow=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        {
            return true;
        }
    }
    return false;
}

9.环形链表2

题目链接:

142. 环形链表 II - 力扣(LeetCode)https://leetcode.cn/problems/linked-list-cycle-ii/description/题目描述:

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

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

不允许修改 链表。

思路:用快慢指针找到相遇节点,利用“相遇节点到头节点的距离==头节点到入环节点的距离”求出入环节点

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *fast=head;
    struct ListNode *slow=head;
    struct ListNode *pcur=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        {
            while(slow!=pcur)
            {
                slow=slow->next;
                pcur=pcur->next;
            }
            return slow;
        }
    }
    return NULL;
}
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值