剑指offer面试题22、23、25:关于链表的一些题目

链表是比较重要的数据结构(也是我掌握得很差的)
在剑指offer上刷了几道题,在这里做个总结:

.

链表中倒数第k个节点

这是leetcode上的一道简单题。
在这里插入图片描述
第一时间的想法:

  • 用一个while循环,计算出链表长度n
  • 再用一个while循环,对头节点进行n-k次next操作,即可求解

但是看过题解之后,发现了一种更简洁的方法,该方法可以不用计算出链表长度,求解如下:

  • 定义两个结点former和latter。former指向头节点,latter指向former后K个元素(例如在示例中,former指向1, latter指向3)
  • 令former和latter同时向后移,当latter指向链表尾元素时,此时former即为所求的结点。

这种方法在我理解就像是用长度为k的绳子把两个结点系住了,当后面的结点为链表尾部结点时,前面的结点自然是倒数第k个元素。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
        former, latter = head, head
        for i in range(k):
            latter = latter.next
        while latter:
            latter = latter.next
            former = former.next
        return former

.

反转链表

在这里插入图片描述
这题重点是想清楚对每一个节点是怎么操作的。只要弄懂了每一个节点上的操作,那么对整个链表就一目了然了。
假设我们正在对1->2->3中的2进行操作,操作有两步

  1. 将2的next赋值为1(即1<-2)
  2. 将指针移动到3(下一步再对3进行操作)

因此我们需要用到两个指针:

  • cur:指向正在操作的元素(假设中的2)
  • pre:指向上一个元素(假设中的1)
  • T:指向下一个要操作的元素(假设中的3)

值得注意的是,因为cur的next指针经过了修改,所以T不能直接由cur的next得到,需要提前保存

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        cur = head
        pre = None
        while cur:
            t = cur.next
            cur.next = pre
            pre = cur
            cur = t
        return pre

.

合并两个排序的链表

这依然是一道…简单题。
在这里插入图片描述
不过这题体现了链表类题目中一个较通用的办法:哨兵节点。

这一题的思想很简单:挨个比较两个链表中的元素,将较小的元素插入到目标链表中,直到两个链表均访问到末尾为止。
但是有一点需要注意:我们该如何建立目标链表?

最直接的想法是:可以在原有的链表基础上进行构建。

例如对A,B链表,指定A为目标链表,在A上进行修改。但这样有个问题,当B中的节点插入到A中时(也就是将A中某节点的next指向B中某节点),此时原A中节点的next指向的节点便丢失了。因此需要预先保存。这其实是不必要的开销。

嘿嘿,这时我们的哨兵节点就要出场了。
虽然名字叫哨兵,但它其实就是一个空节点。之后的插入节点,都是在它的屁股后面插。
这避免了什么问题?因为空节点跟原来的A,B链表都没有关系,所以A,B中的节点可以放心大胆地往里面插——反正不会破坏A,B的内部结构

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeTwoLists(self, l1, l2):
        # maintain an unchanging reference to node ahead of the return node.
        prehead = ListNode(-1)  ## 哨兵节点

        prev = prehead
        while l1 and l2:
            if l1.val <= l2.val:
                prev.next = l1
                l1 = l1.next
            else:
                prev.next = l2
                l2 = l2.next            
            prev = prev.next

        # exactly one of l1 and l2 can be non-null at this point, so connect
        # the non-null list to the end of the merged list.
        prev.next = l1 if l1 is not None else l2

        return prehead.next
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值