leetcode刷题之链表必刷题(python实现)

深藏阁楼爱情的钟 2023-01-13 09:40 200阅读 0赞

最近重新回顾了一下链表,在自己手动写了链表的生成以及相应的增删查改操作后,对链表的理解更加深刻,于是在leetcode上刷了对应的习题。

王争老师列举了一些链表必刷题,感觉有必要做一下这些习题。

链表的必刷题有:

  • 单链表反转
  • 链表中环的检测
  • 两个有序的链表合并
  • 删除链表倒数第n个结点
  • 求链表的中间结点

文章目录

          1. [反转链表](https://leetcode-cn.com/problems/reverse-linked-list/)
          • 递归实现:
          • 迭代实现
          1. [反转链表 II](https://leetcode-cn.com/problems/reverse-linked-list-ii/)
        • 剑指 Offer 22. [链表中倒数第k个节点](https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/)
          • 使用快慢指针
          • 先遍历再取节点
          1. [删除链表的倒数第 N 个结点](https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/)
          1. [链表的中间结点](https://leetcode-cn.com/problems/middle-of-the-linked-list/)
          • 快慢指针法
          • 先遍历再求节点
          1. [合并两个有序链表](https://leetcode-cn.com/problems/merge-two-sorted-lists/)
          1. [环形链表](https://leetcode-cn.com/problems/linked-list-cycle/)
          1. [环形链表 II](https://leetcode-cn.com/problems/linked-list-cycle-ii/)

206. 反转链表

在这里插入图片描述

这道题可以用迭代或者递归实现。

递归和迭代的思路都是不断反转两个节点。

递归实现:
  1. # Definition for singly-linked list.
  2. # class ListNode(object):
  3. # def __init__(self, val=0, next=None):
  4. # self.val = val
  5. # self.next = next
  6. class Solution(object):
  7. def reverseList(self, head):
  8. """ :type head: ListNode :rtype: ListNode """
  9. # 有一个节点或者没有节点时,直接返回列表
  10. if not head or not head.next:
  11. return head
  12. pre, node = head, head.next
  13. while node:
  14. pre, node = self.__reverse_two(pre, node)
  15. head.next = None
  16. head = pre
  17. return head
  18. def __reverse_two(self, pre, node):
  19. # 反转两个节点
  20. tmp = node.next
  21. node.next = pre
  22. pre, node = node, tmp
  23. return pre, node
迭代实现
  1. # Definition for singly-linked list.
  2. # class ListNode(object):
  3. # def __init__(self, val=0, next=None):
  4. # self.val = val
  5. # self.next = next
  6. class Solution(object):
  7. def reverseList(self, head):
  8. """ :type head: ListNode :rtype: ListNode """
  9. if not head or not head.next:
  10. return head
  11. pre, node = head, head.next
  12. while node:
  13. temp = node.next
  14. node.next = pre
  15. pre = node
  16. node = temp
  17. head.next = None
  18. return pre

92. 反转链表 II

在这里插入图片描述

反转链表92的题目可以在反转链表206的题目上修改。

反转的逻辑可以复用。

这里主要是要找到反转的起始节点和终止节点,同时要保存剩下的节点。

  1. # Definition for singly-linked list.
  2. # class ListNode(object):
  3. # def __init__(self, val=0, next=None):
  4. # self.val = val
  5. # self.next = next
  6. class Solution(object):
  7. def reverseBetween(self, head, left, right):
  8. """ :type head: ListNode :type left: int :type right: int :rtype: ListNode """
  9. if not head.next:
  10. return head
  11. fake_head = ListNode(-1)
  12. fake_head.next = head
  13. pre = fake_head
  14. # 得到反转起始节点的前向节点
  15. for i in range(left - 1):
  16. pre = pre.next
  17. reverse_end = pre
  18. # 得到反转终止节点
  19. for i in range(right - left + 1):
  20. reverse_end = reverse_end.next
  21. # 剩余不反转的节点
  22. end_node = reverse_end.next
  23. # 反转起始节点
  24. reverse_start = pre.next
  25. # 反转终止节点指向None, 反转起始节点的前向节点指向None
  26. reverse_end.next = None
  27. pre.next = None
  28. # 反转中间部分的节点
  29. # 反转起始节点reverse_start, 终止是 reverse_end
  30. pre_, node_ = reverse_start, reverse_start.next
  31. while node_:
  32. pre_, node_ = self.__reverse(pre_, node_)
  33. pre.next = pre_
  34. reverse_start.next = end_node
  35. return fake_head.next
  36. # 利用递归反转,也可以使用迭代
  37. def __reverse(self, pre, node):
  38. tmp = node.next
  39. node.next = pre
  40. pre, node = node, tmp
  41. return pre, node

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

在这里插入图片描述

求倒数第k个节点有两种方法,第一种是使用快慢指针,第二种就是先求出链表的长度,再遍历得到对应节点

使用快慢指针

使用快慢指针可以只扫描一次。

  1. # class ListNode(object):
  2. # def __init__(self, x):
  3. # self.val = x
  4. # self.next = None
  5. class Solution(object):
  6. def getKthFromEnd(self, head, k):
  7. """ :type head: ListNode :type k: int :rtype: ListNode """
  8. if not head or not head.next:
  9. return head
  10. fast = slow = head
  11. # 快指针先走k步
  12. for i in range(k):
  13. fast = fast.next
  14. while fast:
  15. slow = slow.next
  16. fast = fast.next
  17. # 当快指针走完的时候,慢指针就位于该节点
  18. return slow
先遍历再取节点
  1. # class ListNode(object):
  2. # def __init__(self, x):
  3. # self.val = x
  4. # self.next = None
  5. class Solution(object):
  6. def getKthFromEnd(self, head, k):
  7. """ :type head: ListNode :type k: int :rtype: ListNode """
  8. if not head or not head.next:
  9. return head
  10. # 先求出链表长度
  11. n = 0
  12. p = head
  13. while p:
  14. p = p.next
  15. n += 1
  16. # 遍历找到k的位置
  17. pos = 0
  18. p = head
  19. while p and k != (n - pos):
  20. p = p.next
  21. pos += 1
  22. return p

19. 删除链表的倒数第 N 个结点

在这里插入图片描述

删除倒数第n个节点也可以使用快慢指针的思路。

  1. # class ListNode(object):
  2. # def __init__(self, val=0, next=None):
  3. # self.val = val
  4. # self.next = next
  5. class Solution(object):
  6. def removeNthFromEnd(self, head, n):
  7. """ :type head: ListNode :type n: int :rtype: ListNode """
  8. # 没有节点或者只有一个节点时直接返回
  9. if not head or not head.next:
  10. return head
  11. fast = slow = head
  12. # 快指针先走n步
  13. for i in range(n):
  14. fast = fast.next
  15. # pre指针用于找到倒数第n个节点的前向节点
  16. pre = ListNode(-1)
  17. while fast:
  18. pre.next = slow
  19. slow = slow.next
  20. fast = fast.next
  21. pre = pre.next
  22. pre.next = slow.next
  23. return head

876. 链表的中间结点

在这里插入图片描述

采用的方法是先求链表长度,再求中间节点。或者快慢指针。
感觉这道题和求倒数第n节点的思想都差不多

快慢指针法

快指针比慢指针多走两步,当快指针走完时,慢指针指向的节点就是中间节点

  1. # class ListNode(object):
  2. # def __init__(self, x):
  3. # self.val = x
  4. # self.next = None
  5. class Solution(object):
  6. def middleNode(self, head):
  7. """ :type head: ListNode :rtype: ListNode """
  8. slow = fast = head
  9. while fast and fast.next:
  10. slow = slow.next
  11. fast = fast.next.next
  12. return slow
先遍历再求节点
  1. # class ListNode(object):
  2. # def __init__(self, x):
  3. # self.val = x
  4. # self.next = None
  5. class Solution(object):
  6. def middleNode(self, head):
  7. """ :type head: ListNode :rtype: ListNode """
  8. n = 0
  9. p = head
  10. while p:
  11. p = p.next
  12. n += 1
  13. mid = n // 2
  14. p = head
  15. pos = 0
  16. while p and pos != mid:
  17. p = p.next
  18. pos += 1
  19. return p

21. 合并两个有序链表

在这里插入图片描述

两个链表分别用指针遍历

  1. # class ListNode(object):
  2. # def __init__(self, val=0, next=None):
  3. # self.val = val
  4. # self.next = next
  5. class Solution(object):
  6. def mergeTwoLists(self, l1, l2):
  7. """ :type l1: ListNode :type l2: ListNode :rtype: ListNode """
  8. fake_head = ListNode(-1)
  9. pre = fake_head
  10. while l1 and l2:
  11. if l1.val <= l2.val:
  12. pre.next = l1
  13. l1 = l1.next
  14. else:
  15. pre.next = l2
  16. l2 = l2.next
  17. pre = pre.next # 写代码的时候遗漏了该指针的移动
  18. # 剩余节点
  19. pre.next = l1 or l2
  20. return fake_head.next

141. 环形链表

在这里插入图片描述

这道题也是使用快慢指针,如果有环,快慢指针最终相遇。

快指针始终比慢指针多走一步

  1. # class ListNode(object):
  2. # def __init__(self, x):
  3. # self.val = x
  4. # self.next = None
  5. class Solution(object):
  6. def hasCycle(self, head):
  7. """ :type head: ListNode :rtype: bool """
  8. # 加上这个判断之后时间更快了
  9. if not head or not head.next:
  10. return False
  11. fast = slow = head
  12. while fast and fast.next:
  13. slow = slow.next
  14. fast = fast.next.next
  15. # 快慢指针相遇说明存在环
  16. if slow == fast:
  17. return True
  18. return False

142. 环形链表 II

在这里插入图片描述

这道题也使用快慢指针,只不过还需要看相遇的节点是第几个节点。

  1. # class ListNode(object):
  2. # def __init__(self, x):
  3. # self.val = x
  4. # self.next = None
  5. class Solution(object):
  6. def detectCycle(self, head):
  7. """ :type head: ListNode :rtype: ListNode """
  8. if not head or not head.next:
  9. return None
  10. fast = slow = head
  11. while fast and fast.next:
  12. slow = slow.next
  13. fast = fast.next.next
  14. if slow == fast:
  15. pre = head
  16. while pre != slow:
  17. pre = pre.next
  18. slow = slow.next
  19. return pre
  20. return None

发表评论

表情:
评论列表 (有 0 条评论,200人围观)

还没有评论,来说两句吧...

相关阅读