反转链表
# -*- 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)