欢迎访问宙启技术站
智能推送

五个经典链表OJ题带你进阶C++链表篇

发布时间:2023-05-14 18:55:08

1.  题目:反转链表

题目描述:

输入一个链表,反转链表后,输出新链表的表头。

示例输入:

1 -> 2 -> 3 -> 4 -> 5

示例输出:

5 -> 4 -> 3 -> 2 -> 1

思路分析:

1、定义三个指针:当前节点指针pNode、当前节点的前一个节点指针pPrev、当前节点的后一个节点指针pNext。

2、遍历链表,将当前节点的指针修改为空时,循环停止;每次将pNode的next指针指向pPrev节点,再将三个指针向后移动。

3、最后返回pPrev节点,也就是反转后的新链表表头。

代码实现:

struct ListNode* ReverseList(struct ListNode* pHead) {

    if(pHead == NULL || pHead->next == NULL) 

        return pHead;

    struct ListNode* pNode = pHead;

    struct ListNode* pPrev = NULL;

    while(pNode != NULL) {

        struct ListNode* pNext = pNode->next;

        pNode->next = pPrev;

        pPrev = pNode;

        pNode = pNext;

    }

    return pPrev;

}

2. 题目:合并两个有序链表

题目描述:

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

示例输入:

1 -> 2 -> 4, 3 -> 5 -> 6

示例输出:

1 -> 2 -> 3 -> 4 -> 5 -> 6

思路分析:

1、将两个链表从头开始比较,较小的元素节点先链接到新的链表中。

2、递归执行比较和链接操作,直到其中一个链表为空。

3、将另一个非空的链表链接到新的链表的末尾。

4、最后返回新建链表的头结点。

代码实现:

struct ListNode* MergeList(struct ListNode* p1, struct ListNode* p2) {

    if(p1 == NULL) 

        return p2;

    if(p2 == NULL) 

        return p1;

    struct ListNode* pNew = NULL;

    if(p1->val < p2->val) {

        pNew = p1;

        pNew->next = MergeList(p1->next, p2);

    } else {

        pNew = p2;

        pNew->next = MergeList(p1, p2->next);

    }

    return pNew;

}

3. 题目:找到链表的倒数第 k 个节点

题目描述:

输入一个链表,输出该链表中倒数第k个结点。

示例输入:

1 -> 2 -> 3 -> 4 -> 5, 2

示例输出:

4 -> 5

思路分析:

1、分别定义两个指针:pAhead 和 pBehind。

2、首先让 pAhead 节点移动 K 个节点,然后 pAhead 节点和 pBehind 节点同时向后移动,直到pAhead节点到链表末端。

3、此时的 pBehind 就是倒数第 K 个节点。

代码实现:

struct ListNode* FindKthToTail(struct ListNode* pListHead, unsigned int k) {

    if(pListHead == NULL) 

        return NULL;

    struct ListNode* pBehind = pListHead;

    struct ListNode* pAhead = pListHead;

    for(int i = 0; i < k - 1; i++){

        if(pAhead->next != NULL) 

            pAhead = pAhead->next;

        else 

            return NULL;

    }

    while(pAhead->next != NULL) {

        pAhead = pAhead->next;

        pBehind = pBehind->next;

    }

    return pBehind;

}

4. 题目:删除链表中重复的结点

题目描述:

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。

示例输入:

1 -> 2 -> 3 -> 3 -> 4 -> 4 -> 5

示例输出:

1 -> 2 -> 5

思路分析:

1、使用一个指针pNode遍历链表,判断当前节点是否与下一个节点重复。

2、如果重复,则删除当前节点和下一个节点,同时将前一个节点的next指向下一个节点。

3、如果不重复,则继续向后遍历。

4、最后返回修改后的链表头指针。

代码实现:

struct ListNode* deleteDuplication(struct ListNode* pHead) {

    if(pHead == NULL) 

        return NULL;

    struct ListNode* pNode = pHead;

    struct ListNode* pPrev = NULL;

    while(pNode != NULL) {

        struct ListNode* pNext = pNode->next;

        if(pNext != NULL && pNode->val == pNext->val) {

            while(pNext != NULL && pNode->val == pNext->val) 

                pNext = pNext->next;

            if(pPrev == NULL) 

                pHead = pNext;

            else 

                pPrev->next = pNext;

        } else {

            pPrev = pNode;

        }

        pNode = pNext;

    }

    return pHead;

}

5. 题目:判断链表中是否有环

题目描述:

给定一个链表,判断链表中是否有环。

示例输入:

1 -> 2 -> 3 -> 4 -> 5 -> 3

示例输出:

true

思路分析:

1、使用快慢指针,如果在遍历中两个指针相遇了,说明链表中存在环。

2、如果快指针pFast遍历过程中到达了链表末端,仍未与慢指针pSlow相遇,则链表中不存在环。

代码实现:

bool hasCycle(struct ListNode *head) {

    if(head == NULL) 

        return false;

    struct ListNode *pSlow = head, *pFast = head->next;

    while(pFast != NULL && pFast->next != NULL) {

        if(pFast == pSlow) 

            return true;

        pSlow = pSlow->next;

        pFast = pFast->next->next;

    }

    return false;

}