链表

链表数据结构

# 链表节点
class ListNode:
    def __init__(self,x):
        self.val=x
        self.next=None

带环的链表

给定一个单链表,只给出头指针head:
1、如何判断是否存在环?
2、如何知道环的长度?
3、如何找出环的连接点在哪里?
4、带环链表的长度是多少?

1. 判断链表是否有环

判断给定的链表中是否有环。

题解:
设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到None退出。

def hasCycle(head):
    fast,slow=head,head
    while fast and fast.next:
        fast=fast.next.next
        slow=slow.next
        if fast==slow:
            return True
    return False

2. 链表中环的长度

记录下问题1的碰撞点,fast从该点开始,再次碰撞所走过的操作数就是环的长度。

def cycleLen(head):
    fast,slow=head,head
    while fast and fast.next:
        fast=fast.next.next
        slow=slow.next
        if fast==slow:
            break
    if not fast or not fast.next:
        return 0
    ans=1
    fast=fast.next
    while slow!=fast:
        ans+=1
        fast=fast.next
    return ans

3. 链表中环的入口节点

因此,分别从碰撞点、头指针开始走,相遇的那个点就是入口节点。

def detectCycle(head):
    fast,slow=head,head
    while fast and fast.next:
        fast=fast.next.next
        slow=slow.next
        if fast==slow:
            break
    if not fast or not fast.next:
        return None
    fast=head
    while fast!=slow:
        fast=fast.next # 从头指针开始移动
        slow=slow.next # 从碰撞指针开始移动
    return fast

4. 带环链表的长度

问题3中已经求出连接点距离头指针的长度,加上问题2中求出的环的长度,二者之和就是带环单链表的长度。

def listLen(head):
    fast,slow=head,head
    while fast and fast.next:
        fast=fast.next.next
        slow=slow.next
        if fast==slow:
            break
    # 环长
    if not fast or not fast.next:
        cycle=0
    else:
        cycle=1
        fast=fast.next
        while slow!=fast:
            cycle+=1
            fast=fast.next
    # 非环部分长度
    ans,fast=0,head
    while slow!=fast:
        fast=fast.next
        slow=slow.next
        ans+=1
    return ans+cycle

反转链表

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

题解:

  • 定义两个指针: pre 和 cur ;pre 在前 cur 在后。
  • 每次让 pre 的 next 指向 cur ,实现一次局部反转。
  • 局部反转完成之后, pre 和 cur 同时往前移动一个位置。
  • 循环上述过程,直至 pre 到达链表尾部。
def ReverseList(head):
    cur,pre=None,head
    while pre:
        tmp=pre.next
        pre.next=cur
        cur,pre=pre,tmp
    return cur

链表中倒数第 k 个结点

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

题解:

  • 初始化: 前指针 pre、后指针 cur ,双指针都指向头节点 head​ 。
  • 构建双指针距离: 前指针 pre 先向前走 k 步(结束后,双指针 pre 和 cur 间相距 k 步),如果链表长度小于 k,则返回None。
  • 双指针共同移动: 循环中,双指针 pre 和 cur 每轮都向前走一步,直至 pre 走过链表尾节点时跳出,跳出后, cur 与尾节点距离为 k-1,即 cur 指向倒数第 k 个节点。
def FindKthToTail(head, k):
    cur,pre=head,head
    for i in range(k):
        if pre:
            pre=pre.next
        else:
            return None
    while pre:
        pre,cur=pre.next,cur.next
    return cur

合并有序链表

将两个有序的链表合并为一个新链表,要求新的链表是通过拼接两个链表的节点来生成的。

题解:

  • 初始化:伪头节点 dum,节点 cur 指向 dum;
  • 循环合并:使用双指针遍历两个链表,当 l1 或 l2 为空时跳出
    • l1.val<l2.val:cur 的后继结点指定为 l1,l1 向前走一步;
    • l1.val>=l2.val:cur 的后继结点指定为 l2,l2 向前走一步;
    • 结点 cur 向前走一步。
  • 合并剩余尾部:跳出时有两种情况,即 l1 为空或 l2 为空
    • 若 l1=None,将 l1 添加至结点 cur 之后;
    • 否则,将 l2 添加至结点 cur 之后.
  • 返回值:合并链表在伪头结点 dum 之后,因此返回 dum.next 即可。
def mergeTwoLists(l1,l2):
    cur=dum=ListNode(0)
    while l1 and l2:
        if l1.val<l2.val:
            cur.next,l1=l1,l1.next
        else:
            cur.next,l2=l2,l2.next
        cur=cur.next
    cur.next=l1 if l1 else l2
    return dum.next

两个链表的第一个公共结点

输入两个链表,找出它们的第一个公共结点。

题解:
使用两个指针 l1,l2 分别指向两个链表 headA,headB 的头结点,然后同时分别逐结点遍历,当 l1 到达链表 headA 的末尾时,重新定位到链表 headB 的头结点;当 l2 到达链表 headB 的末尾时,重新定位到链表 headA 的头结点。

def FindFirstCommonNode(headA,headB):
    l1,l2=headA,headB
    while l1!=l2:
        l1=l1.next if l1 else headB
        l2=l2.next if l2 else headA
    return l1

笔试题:如何判断单链表是否存在环

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值