【算法题】剑指offer之链表--python实现

反转链表

在这里插入图片描述

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        #方法一:
        #相遇于方法二可以节省空间
        tem = None
        rev_head = None
        #pHead相当于cur,表示当前节点
        while pHead:
            #tem临时记录pHead的下一个节点
            tem = pHead.next
            #反转
            pHead.next = rev_head
            #反转之后的链表的首节点的更新
            rev_head =pHead 
            #当前节点继续往下走
            pHead = tem
        return rev_head
        """
        #方法二:
        #新创建一个链表,从头部添加节点
        new_list = None
        while pHead:
            #将数的形式转化为节点的形式
            node = ListNode(pHead.val)
            #在头部添加节点
            node.next = new_list
            #每次都需要让new_list指向新节点的头部
            new_list = node
            #旧链表遍历
            pHead = pHead.next
        return new_list
        """
        

链表中环的入口结点

在这里插入图片描述
解题思路中结论二的证明
设:
链表头到环入口长度为–a
环入口到相遇点长度为–b
相遇点到环入口长度为–c
在这里插入图片描述

则:相遇时
快指针路程=a+(b+c)k+b ,k>=1 其中b+c为环的长度,k为绕环的圈数(k>=1,即最少一圈,不能是0圈,不然和慢指针走的一样长,矛盾)。
慢指针路程=a+b
快指针走的路程是慢指针的两倍,所以:
*(a+b)2=a+(b+c)k+b
化简可得:
a=(k-1)(b+c)+c 这个式子的意思是: 链表头到环入口的距离=相遇点到环入口的距离+(k-1)圈环长度。其中k>=1,所以k-1>=0圈。所以两个指针分别从链表头和相遇点出发,最后一定相遇于环入口。

"""
解题思路--快慢指针法
设置快慢指针,都从链表头出发,快指针每次走两步,慢指针一次走一步,假如有环,一定相遇于环中某点(结论1)。
接着让两个指针分别从相遇点(meet_point)和链表头(head_point)出发,两者都改为每次走一步,最终相遇于环入口(结论2)。
"""
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        slow = pHead
        fast = pHead
        meet_point = pHead
        head_point = pHead
        while fast != None and fast.next != None:
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                meet_point = slow
                while head_point != meet_point:
                    head_point = head_point.next
                    meet_point = meet_point.next
                return head_point

删除链表中的重复节点

在这里插入图片描述

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def deleteDuplication(self, pHead):
        # write code here
        #由于链表可能从第一个节点就开始重复,所以在pHead的头节点之前再增加一个节点
        first = ListNode(-1)
        first.next = pHead
        cur = pHead
        per = first
        while cur and cur.next:
            if cur.val != cur.next.val:
                per = cur
                cur = cur.next
            else:
                #加上下面这句话之后,会保留重复的节点
                #比如链表1->2->3->3->4->4->5 
                #现在的输出为:1->2->5
                #加上下面这句话的输出为:1->2->3->4->5 
                #per = cur
                val = cur.val
                while cur and cur.val == val:
                    cur = cur.next
                per.next = cur
        return first.next

上述代码的完整调试程序

# -*- coding:utf-8 -*-
class Node(object):
    """"节点"""
    def __init__(self,elem):
        self.elem = elem
        self.next = None
        
class Singlelinklist(object):
    """单链表"""

    # 不传入节点时为空列表,因此node的默认值为None
    def __init__(self, node=None):
        # _表示私有属性
        # _head指向列表中的第一个节点
        self._head = node

    def is_empty(self):
        return self._head == None

    def lenth(self):
        # cur表示游标,用来遍历节点
        cur = self._head
        # count用来计数
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        """遍历(打印)整个列表"""
        cur = self._head
        while cur != None:
            print(cur.elem, end=" ")
            cur = cur.next
        print("")

    # 复杂度O(1)
    def add(self, item):
        """列表头部添加元素"""
        node = Node(item)
        # 下面两句话顺序不能改表,改变顺序之后,原有的列表会丢失
        node.next = self._head
        self._head = node
        # 上面个两句话可以用下面这一句话代替
        # self._head,node.next = node,self._head

    # 复杂度O(n)
    def append(self, item):
        """列表尾部添加元素"""
        # 传入的数据,先需要把数据转化为节点
        node = Node(item)
        if self.is_empty():
            self._head = node
        else:
            cur = self._head
            while cur.next != None:
                cur = cur.next
            cur.next = node

    # 复杂度O(n)
    def insert(self, pos, item):
        # pos从0开始索引
        # per表示pos最终指向pos-1的那个位置
        node = Node(item)
        per = self._head
        count = 0
        if pos <= 0:
            self.add(item)
        elif pos > (self.lenth() - 1):
            self.append(item)
        else:
            while count < (pos - 1):
                count += 1
                per = per.next
            # 此时per指向pos-1
            node.next = per.next
            per.next = node

    def remove(self, item):
        # 只删除与之相匹配的第一个,第二个之后出现的不删除
        if self.is_empty():
            return
        cur = self._head
        per = None
        while cur != None:
            # 判断item与节点是否相等
            if cur.elem == item:
                # 如果删除的是第一个结点的话
                if per == None:
                    self._head = cur.next
                else:
                    per.next = cur.next
                break
            else:
                per = cur
                cur = cur.next

    # 复杂度O(n)
    def search(self, item):
        cur = self._head
        while cur != None:
            if cur.elem == item:
                return True
            else:
                cur = cur.next
        return False

# class ListNode:
#     def __init__(self, x):
#         self.elem = x
#         self.next = None
class Solution:
    def deleteDuplication(self, pHead):
        # write code here
        #由于链表可能从第一个节点就开始重复,所以在pHead的头节点之前再增加一个节点
        # first = Node(-1)
        # first.next = pHead
        cur = pHead._head.next
        per = pHead._head
        while cur and cur.next:
            if cur.elem != cur.next.elem:
                per = cur
                cur = cur.next
            else:
                per = cur
                elem = cur.elem
                while cur and cur.elem == elem:
                    cur = cur.next
                per.next = cur
        return pHead._head.next


if __name__ == '__main__':
    s = [-1,1,2,3,3,4,4,5]
    li = Singlelinklist()
    for i in range(len(s)):
        li.append(s[i])
    # print(li)
    answer = Solution()
    a = answer.deleteDuplication(li)
    print(a)

链表中的倒数第k个节点

在这里插入图片描述

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        #方法一:快慢指针
        #先让快指针向前走k个节点(每一步都需要判断是否越界)
        #当快指针到达尾节点时,慢指针到达倒数第k个节点
        slow = head
        fast = head
        for i in range(k):
            if fast:
                fast = fast.next
            else:
                return None
        while fast:
            fast = fast.next
            slow = slow.next
        return slow
        """
        #方法二:
        #先遍历一遍计算链表长度,再输出该链表中倒数第k个结点。
        
        #用于记录链表长度
        count = 0
        cur = head
        while cur:
            cur = cur.next
            count+=1
        if k > count:
            return None
        #经过上面的遍历,per已经指向最后,因此需要在初始化一遍
        cur = head
        for i in range(count-k):
            cur = cur.next
        return cur
        """

反转链表

在这里插入图片描述

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        #新创建一个链表,从头部添加节点
        new_list = None
        while pHead:
            #将数的形式转化为节点的形式
            node = ListNode(pHead.val)
            #在头部添加节点
            node.next = new_list
            #每次都需要让new_list指向新节点的头部
            new_list = node
            #旧链表遍历
            pHead = pHead.next
        return new_list

从尾到头打印链表

在这里插入图片描述

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        res=[]
        while listNode:
            res.append(listNode.val)
            listNode=listNode.next
        return res[::-1]  #逆序打印

笔记
python中[-1]、[:-1]、[::-1]、[2::-1]的使用方法

a=[1,2,3.4,5]
print(a)
[ 1 2 3 4 5 ] 
print(a[-1]) ###取最后一个元素
[5] 
print(a[:-1])  ### 除了最后一个取全部
[ 1 2 3 4 ] 
print(a[::-1]) ### 取从后向前(相反)的元素
[ 5 4 3 2 1 ]
print(a[2::-1]) ### 取从下标为2的元素翻转读取
[ 3 2 1 ]

疑问
为什么下面的代码不行,在牛客网中链表的头节点用什么表示?

cur = listNode.head

显示错误:没有head属性

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
         write code here
         res = []
         if listNode == None:
             return res
         cur = listNode.head
         while cur != None:
             res.append(cur.val)
             cur = cur.next
         return res[::-1]  #逆序打印

合并两个排序的链表

在这里插入图片描述

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        new_head = ListNode(-1)
        root = new_head
        while pHead1 != None and pHead2 != None:
            #下面的判断必须是if pHead1.val > pHead2.val:
            #不能是if pHead1 > pHead2:
            #不能对节点进行比较大小
            if pHead1.val > pHead2.val:
                new_head.next = pHead2
                new_head = new_head.next
                pHead2 = pHead2.next
            else:
                new_head.next = pHead1
                new_head = new_head.next
                pHead1 = pHead1.next
        if pHead1:
                new_head.next = pHead1
        if pHead2:
                new_head.next = pHead2
        return root.next

复杂链表的复制

在这里插入图片描述
思路
在这里插入图片描述

# -*- coding:utf-8 -*-
# class RandomListNode:
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None
class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        # write code here
        if not pHead:
            return None
        #1.在原有链表上进行链表的复制,不处理self.random
        cur = pHead
        while cur:
            clone_node = RandomListNode(cur.label)
            clone_node.next = cur.next
            cur.next = clone_node
            cur = cur.next.next
            
        #2.处理新增复制节点的self.random
        cur = pHead
        while cur:
            cur.next.random = cur.random
            cur = cur.next.next
        
        #进行链表的拆分
        cur = pHead
        clone_list = pHead.next
        while cur:
            clone_node = cur.next           
            cur.next =  clone_node.next 
            if clone_node.next:               
                clone_node.next = clone_node.next.next           
            else:               
                clone_node.next = None           
            cur = cur.next        
            
        return clone_list

二叉树与双向链表

在这里插入图片描述
思路
二叉搜索树的中序遍历为排序列表
在中序遍历的基础上进行稍微改动即可。

#二叉搜索树的中序遍历为排序列表
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def __init__(self):
        self.last_node = None
    def Convert(self, pRootOfTree):
        # write code here
        self.Tinorder(pRootOfTree)
        while pRootOfTree and pRootOfTree.left:
            pRootOfTree = pRootOfTree.left
        return pRootOfTree
    
    def Tinorder(self,cur):
        if not cur:
            return
        self.Tinorder(cur.left)
        #当前节点的左节点指向上一节点
        cur.left = self.last_node;
        #只有当上一个节点不为空时,上一节点的右节点才能指向当前节点
        if self.last_node:
             self.last_node.right = cur;
        self.last_node = cur;
        self.Tinorder(cur.right)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值