LCR 027. 回文链表

本文介绍了如何使用Python创建链表类(LinkedList),实现后部插入(rear_insert)和打印(print)功能。同时,通过Solution类中的isPalindrome方法,利用栈来判断链表是否是回文,展示了链表操作在解决回文问题中的应用。
class ListNode:
    def __init__(self, item):
        self.val = item
        self.next = None


class LinkedList:
    def rear_insert(self, li):
        if not li:
            return None
        head = ListNode(li[0])
        tail = head
        for val in li[1:]:
            node = ListNode(val)
            tail.next = node
            tail = node
        return head

    def print(self, head):
        current = head
        while current:
            print(current.val, end="->")
            current = current.next
        print(None)


li = [1, 2, 1]
l = LinkedList()
res = l.rear_insert(li)


# 通过栈的pop函数解题
class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        stack = []
        tmp = head
        while tmp:
            stack.append(tmp.val)
            tmp = tmp.next

        while head:
            if head.val != stack.pop():
                return False
            head = head.next
        return True


l.print(res)
ll = Solution()
print(ll.isPalindrome(res))

<think> 首先,用户正在询问LCR 023相交链表问题。从引用[3]可以看出,LCR 023是关于找到两个单链表相交的起始节点。 关键引用: - 引用[3]:描述了解决方案:计算两个链表的长度差异,让较长的链表前进到该差异,然后同时遍历两个链表,直到找到相同的节点。 - 引用[2]:提供了另一种方法,使用两个指针,每个链表遍历一个,当它们到达末尾时切换到另一个链表的开头。这种方法不需要显式计算长度。 用户具体提到了“LCR 023相交链表问题”,所以引用[3]是最直接的参考。 我需要构建我的回答: - 根据系统指令,使用中文。 - 结构清晰,逐步解释解决方案。 - 在行内数学表达式中使用$...$,尽管这可能不适用于链表问题,但如果有任何数学部分,确保使用它。 - 生成相关问题。 - 在末尾添加引用标识。 解决方案概述: - 方法1(来自引用[3]):计算长度差异(令$len_A$和$len_B$分别为链表的长度),让较长的链表前进$|len_A - len_B|$步,然后同时遍历直到找到交点。 - 方法2(来自引用[2]):使用双指针;每个指针遍历自己的链表,当到达末尾时切换到另一个链表的开头。如果它们相交,它们将在交点处相遇;如果不相交,它们将同时到达null。 引用[4]讨论的是合并K个排序链表,这与当前问题无关,所以我可以忽略它。 引用[1]提到了LeetCode 160,这是类似的问题(相交链表),所以方法是相关的。 在我的回答中: 1. 解释问题:找到两个单链表相交的起始节点。 2. 描述解决方案步骤。 3. 提供伪代码或代码示例(因为引用中有代码,我可以调整)。 4. 如果需要,讨论复杂性。 5. 生成相关问题。 确保语言是中文。 结构: - 介绍问题。 - 解决方法1:长度差异法。 - 解决方法2:双指针法。 - 比较方法。 - 代码实现(可选)。 - 相关问题。 在引用末尾添加标识:[^1], [^2], [^3]。 最终输出应包括相关问题。 </think> ### LCR 023 相交链表问题解决方案 LCR 023 问题要求找到两个单链表相交的起始节点(即交点)。如果链表不相交,则返回 null。该问题是一个经典的双指针应用场景,常见的解决方案包括 **长度差异法** 和 **双指针法(无需计算长度)**。下面我将逐步解释这两种方法,确保内容可靠并参考了站内资源。 #### 1. **长度差异法(基于引用[3])** 该方法通过计算两个链表的长度差,对齐起点后同时遍历来查找交点。时间复杂度为 $O(m + n)$(其中 $m$ 和 $n$ 分别为链表长度),空间复杂度为 $O(1)$。 **步骤:** - 步骤1: 遍历两个链表,计算长度 $len_A$ 和 $len_B$。 - 步骤2: 计算长度差 $d = |len_A - len_B|$,让较长的链表先前进 $d$ 步。 - 步骤3: 两个指针同时从头遍历剩余节点,直到指针指向同一节点(即交点),或遍历结束(无交点)。 **示例代码(简化版):** ```java public ListNode getIntersectionNode(ListNode headA, ListNode headB) { if (headA == null || headB == null) return null; // 计算链表A的长度 int lenA = 0; ListNode currA = headA; while (currA != null) { lenA++; currA = currA.next; } // 计算链表B的长度 int lenB = 0; ListNode currB = headB; while (currB != null) { lenB++; currB = currB.next; } // 对齐起点:较长的链表前进d步 currA = headA; currB = headB; int d = Math.abs(lenA - lenB); if (lenA > lenB) { for (int i = 0; i < d; i++) { currA = currA.next; } } else { for (int i = 0; i < d; i++) { currB = currB.next; } } // 同时遍历直到交点或结束 while (currA != currB) { currA = currA.next; currB = currB.next; } return currA; // 返回交点或null } ``` #### 2. **双指针法(基于引用[2])** 该方法使用两个指针交替遍历两个链表,时间复杂度同样为 $O(m + n)$,空间复杂度为 $O(1)$。优点是不需显式计算长度,代码更简洁。 **步骤:** - 步骤1: 初始化两个指针 `tempA` 和 `tempB`,分别指向链表A和链表B的头节点。 - 步骤2: 同时遍历:每次移动一步,如果指针到达链表末尾(null),则切换到另一链表的头节点。 - 步骤3: 当指针指向同一节点时(即交点),或两者同时为 null(无交点)时停止。 **示例代码(简化版):** ```java public ListNode getIntersectionNode(ListNode headA, ListNode headB) { if (headA == null || headB == null) return null; ListNode tempA = headA; ListNode tempB = headB; // 遍历直到相遇或同时为null while (tempA != tempB) { tempA = (tempA == null) ? headB : tempA.next; tempB = (tempB == null) ? headA : tempB.next; } return tempA; // 返回交点或null } ``` #### 方法比较 - **长度差异法**:逻辑清晰,易于理解,适用于需要调试的场景;但当链表很长时,额外计算长度可能略微增加开销。 - **双指针法**:代码简洁高效,是LeetCode常见解法;但如果链表长度差异过大,遍历路径可能稍长(但时间复杂度相同)。 在实际应用中,双指针法更常用,因为它避免了长度计算步骤[^2][^3]。 #### 性能分析 两种方法均为 $O(m + n)$ 时间复杂度和 $O(1)$ 空间复杂度,因为它们只使用常数额外空间和指针遍历。如果链表相交,确保在有限步内找到节点;如果不相交,指针最终同时指向 null。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值