【数据结构系列03】链表的回文解构、相交链表

链表的回文结构

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

题目如下图所示:

思路1:数组辅助法

此题也可以先把链表中的元素值全部保存到数组中,然后再判断数组是否为回文。不建议使用这种解法,因为如果没有告诉链表最大长度,则不能同此解法

cpp 复制代码
class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        // write code here
        int a[900] = {0};
        ListNode* cur = A;
        int n = 0;
        //保存链表元素
        while(cur)
        {
            a[n++] = cur->val;
            cur = cur->next;
        }
        //判断数组是否为回文结构
        int begin = 0, end = n-1;
        while(begin < end)
        {
            if(a[begin] != a[end])
                return false;
            ++begin;
            --end;
        }
         
        return true;
    }
};

思路2:快慢指针+反转

首先定位链表的中点,然后将后半部分进行反转操作,最后将前后两段进行逐一比对

cpp 复制代码
#include <cstddef>
class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        if(A == NULL || A->next == NULL)
            return true;
        //找中间节点
        // 使用快慢指针找中间节点
        ListNode* slow = A;
        ListNode* fast = A;
        while (fast->next && fast->next->next) {
            slow = slow->next;
            fast = fast->next->next;
        }
        //对后续节点进行逆置(也可以称作翻转指针的指向),从中间节点的下一个节点开始逆置
        ListNode* phead = NULL;//保存前一个指针的节点
        ListNode* pnext = slow->next;//保存下一个指针的节点
        ListNode* cur = pnext->next;
        while(pnext)
        {
            if(cur == NULL)
            {
                pnext->next = phead;
                break;
            }
            pnext->next = phead;
            phead = pnext;
            pnext = cur;
            cur = cur->next;
        }
        ListNode* pcur = pnext;
        while(pcur != NULL)
        {
            if(A->val != pcur->val)
            {
                return false;
            }
            A = A->next;
            pcur = pcur->next;
        }
        return true;
    }
};

也有一种更简洁的写法:

cpp 复制代码
class PalindromeList {
public:
	bool chkPalindrome(ListNode* A) {
		if (A == NULL || A->next == NULL)
			return true;
		ListNode* slow, *fast, *prev, *cur, *nxt;
		slow = fast = A;
		//找到中间节点
		while (fast && fast->next)
		{
			slow = slow->next;
			fast = fast->next->next;
		}
		prev = NULL;
		//后半部分逆置
		cur = slow;
		while (cur)
		{
			nxt = cur->next;
			cur->next = prev;
			prev = cur;
			cur = nxt;
		}
		//逐点比对
		while (A && prev)
		{
			if (A->val != prev->val)
				return false;
			A = A->next;
			prev = prev->next;
		}
		return true;
	}
};

相交链表

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

题目如下图所示:

思路1:双指针法

判断尾指针是否相交,相交找出第一个交点(地址判断)

时间复杂度O(n)

cpp 复制代码
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    int len1 = 0;
    int len2 = 0;
    struct ListNode *cur1 = headA;
    struct ListNode *cur2 = headB;
    while(cur1)
    {
        len1++;
        cur1 = cur1->next;
    }
    while(cur2)
    {
        len2++;
        cur2 = cur2->next;
    }
    int gap = abs(len1 - len2);//abs在c语言中是求绝对值的
    //目的:不用分具体是哪个链表较长了
    struct ListNode *longlist = headA;
    struct ListNode *shortlist = headB;
    if(len1 < len2)
    {
        longlist = headB;
        shortlist = headA;
    }
    while(gap)
    {
        longlist = longlist->next;
        gap--;
    }
    while(longlist && shortlist)
    {
        if(longlist == shortlist)
        {
            return longlist;
        }
        longlist = longlist->next;
        shortlist = shortlist->next;
    }
    return NULL;
}

思路2:暴力解法

A链表的节点依次跟B链表所有节点比较,A链的某个节点跟B链的某个节点相等,这个节点就是交点(不可以同时比较)

时间复杂度O(n*n)

cpp 复制代码
struct ListNode *p1 = headA;
    struct ListNode *p2 = headB;

    while(p1)
    {
        p2 = headB;//一定要记得这个步骤,否则容易导致p2为空,第二次循环及以后比较的结果都不正确
        while(p2)
        {
            if(p1 == p2)
            {
                return p1;
            }
            p2 = p2->next;
        }
        p1 = p1->next;
    }
    return NULL;

总结

本文通过 相交链表链表的回文结构 两道经典题目,深入分析了链表操作中的不同解法效率:

相交链表解法对比

思路 方法 时间复杂度 空间复杂度 优缺点
思路1 暴力解法 O(m×n) O(1) 简单但效率低
思路2 双指针法 O(m+n) O(1) 最优解,推荐使用

链表的回文结构解法对比

思路 方法 时间复杂度 空间复杂度 优缺点
思路1 数组辅助法 O(n) O(n) 直观易懂
思路2 快慢指针+反转 O(n) O(1) 最优解

✅ 核心收获

  • 双指针法解决相交链表:通过路径拼接,优雅地找到交点

  • 快慢指针+反转解决回文:原地操作,空间O(1)

  • 边界处理:链表为空的处理、奇偶长度的处理

  • 面试技巧:先给出直观解法,再逐步优化到最优解


📌 下期预告

下一期我们将继续 【数据结构系列04】 ,进入链表进阶专题(二),一起来看看三道经典题目:

  1. 【复制带随机指针的链表】:如何深度拷贝一个带有随机指针的复杂链表?

  2. 【判断链表中是否有环】:如何检测链表中是否存在环?

  3. 【环形链表 II】:如果链表有环,如何找到环的入口节点?

如果你对链表操作还有疑问,欢迎在评论区留言讨论!如果觉得有帮助,别忘了点赞、收藏、关注,我们下期见!

相关推荐
fu的博客2 小时前
【数据结构4】单向循环链表实现
数据结构·链表
努力学算法的蒟蒻2 小时前
day87(2.16)——leetcode面试经典150
数据结构·leetcode·面试
追随者永远是胜利者2 小时前
(LeetCode-Hot100)17. 电话号码的字母组合
java·算法·leetcode·职场和发展·go
不想看见4042 小时前
Shortest Bridge -- 广度优先搜索 --力扣101算法题解笔记
算法·leetcode·宽度优先
流云鹤2 小时前
2026牛客寒假算法基础集训营5(B D G J F )
算法
教男朋友学大模型2 小时前
LoRA 为什么必须把一个矩阵初始化为0
人工智能·算法·面试·求职招聘
得一录2 小时前
Python 算法高级篇:布谷鸟哈希算法与分布式哈希表
python·算法·aigc·哈希算法
啊吧啊吧abab2 小时前
二分查找与二分答案
c++·算法·二分
AC赳赳老秦2 小时前
2026 智能制造趋势:DeepSeek 助力“黑灯”工厂运营,实现生产流程自动化
网络·数据结构·算法·安全·web安全·prometheus·deepseek