【leetcode总结】解析链表系列

目录

19. 删除链表的倒数第N个节点(medium)

203. 移除链表元素(easy)

237. 删除链表中的节点(easy)

206. 反转链表(easy)

92. 反转链表 II(medium)

160. 相交链表(easy)

141. 环形链表(easy)

142. 环形链表 II(medium)

剑指 Offer 06. 从尾到头打印链表(easy)

83. 删除排序链表中的重复元素(easy)

剑指 Offer 24. 反转链表(easy)

剑指 Offer 52. 两个链表的第一个公共节点(easy)

剑指 Offer 25. 合并两个排序的链表(easy)

剑指 Offer 35. 复杂链表的复制(medium)

剑指 Offer 22. 链表中倒数第k个节点(easy)


19. 删除链表的倒数第N个节点(medium)

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5. 

【注意】[1] 1,这种删除头结点的情况

 进阶:一次扫描出结果(通过构造哑结点dummy)

构建双指针p1p2p1先走n步,然后一同运动,当p1指向表尾,p2指向的next即是倒数第N个节点,删除即可。

[LeetCode] 19. Remove Nth Node From End of List 删除链表的倒数第N个节点 @python 

203. 移除链表元素(easy)

删除链表中等于给定值 val 的所有节点。

输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5
def removeElements(self, head: ListNode, val: int) -> ListNode:
    if not head:return head
    dummy = ListNode(0)
    dummy.next = head
    prev = dummy
    while prev.next:
        if prev.next.val == val:
            prev.next = prev.next.next
        else:
            prev = prev.next
    return dummy.next

整个代码的调用从main开始写起,不太会。。。研究了一下午(?),看这里!here(*^▽^*)

237. 删除链表中的节点(easy)

输入:head = [4,5,1,9], node = 5
输出:[4,1,9]
解释:给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9

class Solution(object):
    def deleteNode(self, node):
        # 只有对要删除节点node的访问权限
        """
        :type node: ListNode
        :rtype: void Do not return anything, modify node in-place instead.
        """
        # 题目给的是删除节点,那说明这个节点可以舍弃了,我们把下一个节点的值拷贝
        # 给当前要删除的节点,再删除下一个节点。
        node.val = node.next.val
        node.next = node.next.next

206. 反转链表(easy)

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

动态图有助于理解:206. 反转链表 - NuoHui的文章 - 知乎

迭代法:

  1. 尾节点指好,防止丢失节点;
  2. 当前节点,反指;
  3. 前节点后移;
  4. 尾节点后移;

初始赋值

    def reverseList(self, head):
        if not head: return head
        prev = None
        cur = head
        while cur:
            tail = cur.next
            cur.next = prev
            prev = cur
            cur = tail
        return prev

递归法:

当遍历到尾结点时,开始往回走

    def recursive(self, head):
        if (head == None or head.next == None):
            return head
        # new_head指向linklist尾结点
        new_head = self.recursive(head.next)
        head.next.next = head
        head.next = None
        return new_head

92. 反转链表 II(medium)

 from   Leetcode 92:反转链表 II

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

说明: 1 ≤ m ≤ n ≤ 链表长度。

输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
	if not head:return head

	prev = None
	cur = head

	i = 1
	while i<m and cur:
		prev = cur
		cur = cur.next
		i+=1

	# tag 做标记
	p1 = prev
	p2 = cur 

	while i<=n and cur:  # 正常反转链表操作
		tail = cur.next
		cur.next = prev
		prev = cur
		cur = tail
		i+=1

	# 特殊判断,如果是头结点开始
	if m == 1:
		p2.next = cur
		return prev
	
	p2.next = cur
	p1.next = prev

	return head

160. 相交链表(easy)

思路:

def getIntersectionNode(self, headA, headB):
    lenA, lenB = 0, 0
    pA = headA
    pB = headB
    while pA:
        pA = pA.next
        lenA += 1
    while pB:
        pB = pB.next
        lenB += 1
    pA = headA
    pB = headB
    if lenA > lenB:
        for i in range(lenA - lenB):
            pA = pA.next
    else:
        for i in range(lenB - lenA):
            pB = pB.next
    while pA != pB:
        pA = pA.next
        pB = pB.next
    return pA

160题目求解

https://leetcode-cn.com/problems/intersection-of-two-linked-lists/solution/160xiang-jiao-lian-biao-shuang-zhi-zhen-ha-xi-biao/ 图解双指针

def double_pointer(self, headA, headB):
	if (not headA or not headB):
		return None
	# 定义两个指针, 第一轮让两个到达末尾的节点指向另一个链表的头部, 最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差)
	# 两个指针等于移动了相同的距离, 有交点就返回, 无交点就是各走了两条指针的长度
	pA = headA
	pB = headB

	# 在这里第一轮体现在pA和pB第一次到达尾部会移向另一链表的表头, 而第二轮体现在如果pA或pB相交就返回交点, 不相交最后就是null == null
	while pA != pB:
		pA = pA.next if pA else headB
		pB = pB.next if pB else headA

	return pA

141. 环形链表(easy)

142. 环形链表 II(medium)

关于环形链表问题的总结,from神不烦 and Rotten_Pencil 
1.快慢指针一直到相遇时的循环次数等于环的长度。(可推导)  

2.快慢指针相遇点到环入口的距离 = 链表起始点到环入口的距离。(可推导)

- 判断是否为环形链表 
思路:使用追赶的方法,设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。 

- 若为环形链表,求环入口点 
思路:快慢指针相遇点到环入口的距离 = 链表起始点到环入口的距离 

- 求环的长度 
思路:记录下相遇点p,slow、fast从该点开始,再次碰撞所走过的操作数就是环的长度s 

- 判断两个链表是不是相交

思路:如果两个链表相交,那么这两个链表的尾节点一定相同。直接判断尾节点是否相同即可。这里把这道题放在环形链表,因为环形链表可以拆成Y字的两个链表。

 代码:141

class Solution(object):
    def hasCycle(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """

        p1 = head # 慢指针
        p2 = head # 快指针
        # while p1 and p2:
        while p2 and p2.next:
            # 为什么这样判断可以??
            p1 = p1.next
            p2 = p2.next.next
            # 如何判断遇见两次了呢?已解
            if p1 == p2:
                return True
        return False

代码142:

class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        # 环入口怎么求?
        # 快慢指针的相遇点到环入口的距离 == 链表起始点到环入口的距离

        p1 = head   # 慢指针
        p2 = head   # 快指针
        encounter = head
        flag = 0
        while p2 and p2.next:
            p1 = p1.next
            p2 = p2.next.next
            if p1 == p2:
                # 相遇点
                encounter = p1
                flag = 1
                break
        if not flag:
            return None

        # print(encounter.val) # -4
        start = head
        pos = 0
        while start and encounter:
            if start == encounter:
                pos += 1
                # return pos # # 返回相遇节点的位置
                return start # 返回相遇点(ac)
            start = start.next
            encounter = encounter.next
        # return -1 # 返回相遇节点的位置
        return None

剑指 Offer 06. 从尾到头打印链表(easy)

# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
    rs = []
    if not ListNode:return rs
    while listNode:
        rs.append(listNode.val)
        listNode = listNode.next
    return rs[::-1]

83. 删除排序链表中的重复元素(easy)

q是不重复节点的第一个位置。

a 和 c 的长度是1。

# -*- coding:utf-8 -*-
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
class Solution:
    def deleteDuplication(self, pHead):
        # write code here
        if not pHead:return pHead
        dummy = ListNode(-1)
        dummy.next = pHead
        p = dummy
        while p.next:
            # 原来错误是while dummy.next:
            # dummy在while中都没有发生改变,起不到循环结束的作用
            q = p.next
            while (q and p.next.val == q.val):
                q = q.next
            # 如果不存在重复,长度==1
            if p.next.next == q:
                p = p.next
            # 如果存在重复,长度>1
            else: p.next = q
        return dummy.next

剑指 Offer 24. 反转链表(easy)

class Solution:
    def ReverseList(self, pHead):
        # 反转链表需要三个listnode
        pre = None
        cur = pHead
        while cur:
            tail = cur.next
            cur.next = pre
            pre = cur
            cur = tail
        # return cur # cur目前指的是空
        return pre

剑指 Offer 52. 两个链表的第一个公共节点(easy)

class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        if not pHead1:return pHead1
        if not pHead2:return pHead2
        len1 = self.getLength(pHead1)
        len2 = self.getLength(pHead2)
        diff = abs(len1-len2)
        p1 = pHead1
        p2 = pHead2
        if len1>len2:
            while diff>0:
                diff -= 1
                p1= p1.next
        if len1<len2:
            while diff>0:
                diff -= 1
                p2 = p2.next
        # print(p1.val)
        # print(p2.val)
        while p1 != p2:
            p1 = p1.next
            p2 = p2.next
        return p1
 
    def getLength(self,head):
        cnt = 0
        cur = head
        while cur:
            cnt+=1
            cur = cur.next
        return cnt

剑指 Offer 25. 合并两个排序的链表(easy)

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        p1,p2 = None,None
        rs = None
        head = rs
        while pHead1 and pHead2:
            if pHead1.val < pHead2.val:
                rs.next = pHead1
                pHead1 = pHead1.next
            else:
                rs.next = pHead2
                pHead2 = pHead2
            rs = rs.next
        while pHead1:
            rs.next = pHead1
        while pHead2:
            rs.next = pHead2
        return head

剑指 Offer 35. 复杂链表的复制(medium)

class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        if not pHead:return None
        p = pHead
        # 完成节点复制
        while p:
            node = RandomListNode(p.label)
            tail = p.next
            p.next = node
            node.next=tail
            p = tail
        # 复制随机指针
        q = pHead
        while q:
            if q.random:
                q.next.random = q.random.next
            q = q.next
        # 开始连接复制的节点
        cloNode = pHead
        pHead = pHead.next
        while cloNode.next:
            node = cloNode.next
            cloNode.next = node.next
            cloNode = node
        return pHead

剑指 Offer 22. 链表中倒数第k个节点(easy)

class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        if not head:return head
        p = head
        cnt = 0
        while p:
            cnt += 1
            p = p.next
        if k>cnt:return
        n = cnt-k+1
        dummy = ListNode(-1)
        dummy.next = head
        q = dummy
        cnt = 0
        while q.next:
            cnt += 1
            if cnt==n:
                return q.next.val
            q = q.next

链表中环入口的位置

class Solution:
    def EntryNodeOfLoop(self, pHead):
 
        p1 = pHead #slow
        p2 = pHead #fast
        meet = pHead
        flag = 0
        while p2 and p2.next:
            p1 = p1.next
            p2 = p2.next.next
            if p1 == p2:
                flag = 1
                meet = p1
                break
        if not flag:
            return None
 
        start = pHead
        while meet and start:
            if meet == start:
                return start
            meet = meet.next
            start = start.next
        return None

【数据结构与算法】面试之链表问题集锦(下) 

附上别人已经总结好的:小小搬运工——链表

本blog的单独链接

https://blog.csdn.net/weixin_31866177/article/details/99711772

https://blog.csdn.net/weixin_31866177/article/details/85923889

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值