LeetCode 有关链表的算法题目(C++)

本文详细探讨了LeetCode中涉及链表的算法题目,包括反转链表、合并两个有序链表、环形链表的判断与处理、删除排序链表中的重复元素等经典问题。通过实例代码解析,展示了各种问题的解题思路和解决方案,旨在帮助读者掌握链表操作技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、反转链表

问题描述

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

代码实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
   
public:
    ListNode* reverseList(ListNode* head) {
   
        if(head == NULL)
            return NULL;
        if(head->next == NULL)
            return head;
        ListNode* p = reverseList(head->next); // p最终指向了尾结点
        head->next->next = head; // 向回指向 
        head->next = NULL; // 原来顺序的指针断掉
        return p; // 返回最为顺序指向尾结点指针 此时作为头指针的p指针
    }
};

运行截图

在这里插入图片描述

非递归(迭代)写法

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
   
public:
    ListNode* reverseList(ListNode* head) {
   
        if(head == NULL)
            return NULL;
        ListNode* pcur = head, *pnext = pcur->next;
        pcur->next = nullptr;
        while(pnext){
               
            ListNode* ptmp = pcur;
            pcur = pnext;
            pnext = pnext->next;
            pcur->next = ptmp;            
        }
        return pcur;
    }
};

运行截图

在这里插入图片描述

2、反转链表 II

问题描述

反转从位置mn 的链表。请使用一趟扫描完成反转。

说明:
1 ≤ m ≤ n ≤ 链表长度

示例:

输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出:1->4->3->2->5->NULL

解题思路

用善意题目迭代的方法,但要注意分两种情况讨论:(1)m == 1时,需要改动头指针;(2)m != 1时,无需改动头指针。

算法实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    //建立伪头结点
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
   
        if(head->next == nullptr)
            return head;
        ListNode* h = new ListNode(0);
        h->next = head;
        ListNode* p = h;
        head = nullptr;
        int i = 1;
        for(; i < m; i++)
            p = p->next; // 让p指向m的前一个结点
        ListNode* pbegin = p->next, *pcur = pbegin, *pend = pcur->next;
        for(; i < n; i++){
   
            ListNode* ptmp = pcur;
            pcur = pend;
            pend = pend->next;
            pcur->next = ptmp;
        }
        p->next = pcur;
        pbegin->next = pend;
        return h->next;        
    }
};

运行截图

在这里插入图片描述

3、合并两个有序链表

问题描述

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

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

解题思路

  • 链表的兼并是老生常谈的问题,却总是费时间完成。对于不带头结点的链表来说,需要建立一个伪头结点作为合并链表后的头结点。
  • 考虑其中一个链表为空的情况,直接返回另一个链表。
  • 定义两个动态指针指向两个链表表头,设置tail指针作为尾插法的尾指针。
  • 比较两个动态指针所指向结点值的大小,较小的值是待插入结点,方法就是尾插法。

代码实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
   
public:
    ListNode* mergeTwoLists(ListNode *a, ListNode *b) {
   
        if (a == nullptr or b == nullptr) 
            return a ? a : b;
        ListNode head, *tail = &head, *aPtr = a, *bPtr = b;
        while (aPtr and bPtr) {
   
            if (aPtr->val < bPtr->val) {
   
                tail->next = aPtr; 
                aPtr = aPtr->next;
            }
            else{
   
                tail->next = bPtr;
                bPtr = bPtr->next;
            }
            tail = tail->next;
        }
        tail->next = (aPtr ? aPtr : bPtr);
        return head.next;
    }
};

运行截图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值