码迷,mamicode.com
首页 > 其他好文 > 详细

线性表(七):链表的经典例题

时间:2020-10-12 20:43:13      阅读:33      评论:0      收藏:0      [点我收藏+]

标签:介绍   影响   反转   实现   lis   and   计算   str   elf   

引言

线性表(三)——线性表(六)这四节笔者介绍了链表的实现及变形,本节将简单介绍几种链表的应用。

反转链表

问题来源:
力扣:206. 反转链表

问题简述:
给定一个链表,请将这个链表反转。

问题分析:
在顺序表中,我们常采用的反转手段是根据索引交换列表的前半段和后半段实现反转。但链表的存储方式不同于顺序存储,那么我们该如何做呢?
一般而言,方法主要有两种:

  1. 迭代式
  • 设置当前游标cur,前驱节点pre
  • 当cur非None时循环,临时存储cur的下一个节点,然后将下一个节点修改为pre
  • 将pre赋值为cur,此时cur的下一个节点为之前的pre
  • 游标后移,直到迭代结束,返回pre
  1. 递归式
  • 如果链表仅有一个元素,直接返回
  • 递归到倒数第二个节点开始反向操作,head.next.next = head实现链表反转,head.next = None断开与后继节点的链接防止形成环
  • 递归结束,返回

Python实现:

# 迭代式
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if not head:
            return
        pre = None
        cur = head
        while cur:
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        return pre

# 递归式
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if not head or not head.next:
            return head
        nextNode = self.reverseList(head.next)
        head.next.next = head
        head.next = None
        return nextNode 

模拟竖式计算

问题来源:
力扣:2. 两数相加

问题简述:
将两个数分别逆序存储在两个链表中,请以链表的形式返回这两个数的和。

问题分析:
实现这一操作并不难,但有几个细节需要注意:

  • 十进制计算需要保存进位数
  • 如果末尾进1(逆序)需要扩展链表,所以循环时要判断进位数是否为0
  • 需要新建一个链表以方便处理头部节点

Python实现:

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        res = ListNode(0)
        cur = res # 游标
        carry = 0 # 进位数
        while l1 or l2 or carry:
            residual1 = l1.val if l1 else 0
            residual2 = l2.val if l2 else 0
            cur.next = ListNode((residual1+residual2+carry) % 10)
            carry = (residual1 + residual2 + carry) // 10
            l1 = l1.next if l1 else None
            l2 = l2.next if l2 else None
            cur = cur.next
        return res.next

寻找环起点

问题来源:
力扣:142. 环形链表

问题简述:
给定一个链表,判断是否存在环,若存在,找出环起点。

问题简述:
笔者在第一次碰到这个问题的时候想法是直接使用哈希表记录经过的结点,第一次碰到的重复的结点一定是环起点,但这样做的坏处是无法在O(1)空间下解决这一问题。
仔细思考,我们会发现通过快慢指针可以优化空间,利用快慢指针可以迅速判环,如果存在换且快慢指针第一次相遇,通过数学推导会发现此时慢指针与环起点的距离同链表起点与环起点的距离“相同”,因此再设置第三个指针与慢指针同向移动即可到达环起点。

Python实现:

class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        # 判环
        cur1, cur2 = head, head
        while cur2 and cur2.next:
            cur1 = cur1.next
            cur2 = cur2.next.next
            if cur1 == cur2:
                break
        if cur2 is None or cur2.next is None:
            return

        # 快指针走的路是慢指针的两倍,它们走的非环路相同,且慢指针在绕环第一圈必定与快指针相遇
        # 设非环路为s,环起点至相遇点为x,相遇点至环起点为y,快指针绕圈数为n
        # 公式2*(s+x) = s + x + n*(x+y) ==> s = y + (n-1)*(x+y) 
        # 推导公式后一部分为环的整数倍,因此不影响计算,可以得知当第一次相遇时慢指针距离环口s步
        # 设置一个新指针指向链表起点,与慢指针同向同速移动,移动y + (n-1)*(x+y)步必定相遇于环口
        # 寻找环起点
        cur3 = head
        while cur3 != cur1:
            cur1 = cur1.next
            cur3 = cur3.next
        return cur1

线性表(七):链表的经典例题

标签:介绍   影响   反转   实现   lis   and   计算   str   elf   

原文地址:https://www.cnblogs.com/yiwen-statistics/p/13804048.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!