python链表和树实验总结_链表总结

总结了常考的十一种操作:判断是否有环

找环的入口

找到中点

找到倒数第K个结点

逆序链表

删除倒数第K个结点

将有序链表转成搜索二叉树

合并两个有序链表

判断是否回文

旋转链表

相交链表

其中找中间结点,倒数第k个结点,逆序链表这三个操作最常用,通过组合可以解决链表的绝大部分问题,并利用哑结点这个小技巧避免空链表与一个结点的链表。

1. 判断是否有环,leetcode141

思路:快慢指针,fast走两步,slow走一步。如果无环快指针最终会遇到null,若有环快指针最终会超慢指针一圈,和慢指针相遇。

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def hasCycle(self, head: ListNode) -> bool:

slow, fast = head, head

while(fast!=None and fast.next!=None):

slow = slow.next

fast = fast.next.next

if (slow == fast):

return True

return False

2. 找环的入口,leetcode142

思路:快慢指针,快的两步,慢的一步,当有环时他俩会相遇,此时快指针走的步数2k是慢指针k的两倍,设相遇点距离入口为m,则入口距离起点为k-m,巧的是环的长度为k,因为快指针比慢指针多绕了一环,所以多出来的就是环的长度,所以从相遇点继续前进k-m步,也恰好到环起点。所以只需把其中一个指针重置为起点,然后同步向前,再次相遇的时候就是入口。

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def detectCycle(self, head: ListNode) -> ListNode:

fast, slow = head, head

while(fast!=None and fast.next!=None):

fast = fast.next.next

slow = slow.next

if slow == fast:

break

if fast == None or fast.next == None:

return

slow = head

while(slow!=fast):

slow = slow.next

fast = fast.next

return slow

3. 找中点(常用技巧),leetcode876

思路:快慢指针,fast走两步,slow走一步,当fast走到链表最后一个结点是,slow为中间结点。

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def middleNode(self, head: ListNode) -> ListNode:

slow, fast = head, head

while(fast!=None and fast.next!=None):

fast = fast.next.next

slow = slow.next

return slow

4. 倒数第k个结点,剑指offer22

思路:快慢指针同时指向头结点,fast先走k步,此时fast和slow距离即为k,然后一直遍历节点到fast指向null,因为俩指针距离k,所以此时慢指针的位置即为倒数第k个结点。

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:

slow, fast = head, head

while(k):

fast = fast.next

k-=1

while(fast):

fast = fast.next

slow = slow.next

return slow

5. 逆序链表,leetcode206

思路一:迭代,搞一个辅助结点先指向null,类似于空瓶子倒水,注意每一步保存原始的head.next,不然将head.next改变指向后会找不到原来的下个结点。

思路二:递归,因为逆序所以要递归到最深再操作,相当于后序,后序操作为改变当前结点下一个结点的指向,并将当前结点指向null;终止条件是递归到最后一个结点,然后返回最后一个结点。最终逆序结束的返回为最后一个结点。

切记,python中递归调用自身要加self.

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def reverseList(self, head: ListNode) -> ListNode:

# 迭代

# pre = None

# while(head):

# temp = head.next

# head.next = pre

# pre = head

# head = temp

# return pre

# 递归

if not head or not head.next:

return head

p = self.reverseList(head.next)

head.next.next = head

head.next = None

return p

6. 删除倒数第k个结点,leetcode19

思路:利用快慢指针找到倒数第k个结点的前一个结点,即k+1,然后将其next指针指向下下个结点即可。按照找倒数第K个的方法,将判别条件改成fast.next!=null,找到的就是倒数第k+1个结点,不用再在slow前创建一个pre指针了,但当输入链表只有一个时容易报错,fast已经是null,没有next属性会报错,所以需要创建哑结点。

Note:这里用到了一个常用技巧,创建哑结点指向head,即dummy.next = head,可以有效防止链表为空或者链表仅有一个值的特殊情况。

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:

dummy = ListNode(0)

dummy.next = head

slow = dummy

fast = dummy

while(n):

fast = fast.next

n -= 1

while(fast.next): # 判断条件变了,找到的是倒数第k个结点的前一个

slow = slow.next

fast = fast.next

slow.next = slow.next.next

return dummy.next

7. 将有序链表转成搜索二叉树,leetcode109

给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。一个高度平衡二叉树是指一个二叉树每个节点的左右两个子树的高度差的绝对值不超过 1。

思路:因为有序链表,且搜索二叉树特点就是中序遍历完是个有序列表。因为高度平衡,所以左右子树不能差1,所以每次重建的时候选取链表的中间结点作为根节点,前半部分为左子树,后半部分为右子树,依次递归即可。

# class ListNode:

# def __init__(self, val=0, next=None):

# self.val = val

# self.next = next

# Definition for a binary tree node.

# class TreeNode:

# def __init__(self, val=0, left=None, right=None):

# self.val = val

# self.left = left

# self.right = right

class Solution:

def sortedListToBST(self, head: ListNode) -> TreeNode:

if not head: return

if not head.next: return TreeNode(head.val)

fast = head

slow = head

preslow = head

while(fast and fast.next):

preslow = slow

fast = fast.next.next

slow = slow.next

root = TreeNode(slow.val)

if preslow:

preslow.next = None

root.left = self.sortedListToBST(head)

root.right = self.sortedListToBST(slow.next)

return root

8. 合并两个有序链表,leetcode21

思路1:暴力法,遍历比较l1和l2两个链表的每个结点,因为是有序的,所以当一个比较完时,剩的那个链表的所有结点一定大。直接链到后边即可。

# class ListNode:

# def __init__(self, val=0, next=None):

# self.val = val

# self.next = next

class Solution:

def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:

head = ListNode(0)

prehead = head

while(l1 and l2):

if l1.val <= l2.val:

head.next = l1

l1 = l1.next

elif l1.val > l2.val:

head.next = l2

l2 = l2.next

head = head.next

if l1:

head.next = l1

elif l2:

head.next = l2

return prehead.next

思路2:递归,见等价子方程,结束条件为递归到null

list1[0]+merge(list1[1:],list2) list1[0]

list2[0]+merge(list1,list2[1:]) otherwise

class Solution:

def mergeTwoLists(self, l1, l2):

if l1 is None:

return l2

elif l2 is None:

return l1

elif l1.val < l2.val:

l1.next = self.mergeTwoLists(l1.next, l2)

return l1

else:

l2.next = self.mergeTwoLists(l1, l2.next)

return l2

​9. 判断是否回文,leetcode234

思路:先用快慢指针找到中间结点,注意偶数的话找后边的那个结点,然后把中间以后的后半部分链表反转,然后遍历后半部分的链表,判断每个结点的值是否相等。

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def isPalindrome(self, head: ListNode) -> bool:

fast, slow = head, head

while(fast and fast.next):

fast = fast.next.next

slow = slow.next

post = self.reverseList(slow)

while(post):

if not post.val == head.val:

return False

post = post.next

head = head.next

return True

def reverseList(self,head):

if not head or not head.next:

return head

p = self.reverseList(head.next)

head.next.next = head

head.next = None

return p

10. 旋转链表,leetcode61

给定一个链表,旋转链表,将链表每个节点向右移动 k个位置,其中 k是非负数。

输入:1->2->3->4->5->NULL, k = 2

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

思路:因为k可能会超出链表长度,所以计算出链表长度len,然后k对len求余得到真实旋转的长度。观察可以发现,右移k个位置其实就是把倒数第k个结点作为头结点,倒数k+1个结点作为尾结点并指向null,为了找到倒数第k+1个结点,使用fast.next作为结束条件。

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def rotateRight(self, head: ListNode, k: int) -> ListNode:

if not head:

return head

length = 0

fast = head

slow = head

aux = head

while(aux):

aux = aux.next

length += 1

k %= length

while(k):

fast = fast.next

k -= 1

while(fast.next):

fast = fast.next

slow = slow.next

fast.next = head

head = slow.next

slow.next = None

return head

11. 相交链表,leetcode160

思路1:遍历其中一个链表,将其每个结点存入字典中,然后遍历另一个当其结点存在于字典中返回该结点,如果都不存在返回None。

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:

dict = {}

while(headA):

dict[headA] = 1

headA = headA.next

while(headB):

if headB in dict:

return headB

headB = headB.next

return None

思路2:让两个链表一起走,当其中一个A走到尾时,另一个链表B走的路径正好为链表A的长度。然后将A的指针pA置为B的头结点,此时pB指针和pA指针的距离差即为A的长度,然后继续同步遍历俩个指针,当pB达到B尾部时,将其置为A的头结点,此时pA到B的尾部的距离即为A的长度,pB到A的尾部的距离也为A的长度。然后再同步走两个指针,当指向的两个结点的值相等时,即为交点。

class Solution(object):

def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:

ha, hb = headA, headB

while ha != hb:

ha = ha.next if ha else headB

hb = hb.next if hb else headA

return ha

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值