程序员代码面试指南 python实现(第二章:链表问题)
- 程序员代码面试指南 python实现(第二章:链表问题)
- 打印两个有序链表的公共部分
- 在单链表和双链表中删除倒数第K个结点
- 单链表
- 双链表
- 删除链表的中间节点和a/b处的节点
- 删除中间节点
- 进阶
- 反转单向和双向链表
- 单向链表
- 双向链表
- 反转部分单向链表
- 环形单链表的约瑟夫环问题
- 原问题
- 进阶
- 判断一个链表是否为回文结构
- 进阶
- 将单向链表按某值划分成左边小、中间相同、右边大的形式
- 原问题
- 进阶
- 复制含有随机指针节点的链表
- 原问题
- 进阶
- 两个单链表生成相加链表
- 方法一:利用栈
- 方法二:利用逆序
- 两个单链表相交的一系列问题
- 判断是否有环,并返回该节点
- 两个无环链表是否相交
- 判断两个有环链表是否相交,返回第一个相交节点
- 主题干
- 将单链表的每K个节点之间逆序
- 方法一:利用栈结构的解法
- 方法二:不需要栈结构,在原链表中直接调整
- 删除无序链表中值重复出现的节点
- 方法一:利用哈希表
- 类似于选择排序过程
- 在单链表中删除指定值的节点
- 方法一:利用栈等容器类
- 方法二:不用任何容器类
- 将搜索二叉树转换成双向链表
- 方法一:队列+二叉树中序遍历
- 方法二:递归
- 单链表的选择排序
- 一种怪异的节点删除方式
- 向有序的环形单链表中插入新节点
- 合并两个有序的单链表
- 按照左右半区的方式重新组合单链表
程序员代码面试指南 python实现(第二章:链表问题)
打印两个有序链表的公共部分
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def printCommonPart(self,head1,head2):
while head1 != None and head2 != None:
if head1.val < head2.val:
head1 = head1.next
elif head1.val > head2.val:
head2 = head2.next
else:
print(str(head1.val)+' ')
head1 = head1.next
head2 = head2.next
if __name__ == "__main__":
A_node_1 = Node(1)
A_node_2 = Node(2)
A_node_3 = Node(3)
A_node_4 = Node(4)
A_node_5 = Node(5)
A_node_1.next = A_node_2
A_node_2.next = A_node_3
A_node_3.next = A_node_4
A_node_4.next = A_node_5
B_node_1 = Node(2)
B_node_2 = Node(3)
B_node_3 = Node(4)
B_node_4 = Node(5)
B_node_5 = Node(6)
B_node_1.next = B_node_2
B_node_2.next = B_node_3
B_node_3.next = B_node_4
B_node_4.next = B_node_5
solu = Solution()
solu.printCommonPart(A_node_1,B_node_1)
在单链表和双链表中删除倒数第K个结点
单链表
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def removeLastKthNode(self,head,lastKth):
if head == None or lastKth < 1:
return head
cur = head
while cur != None:
lastKth -= 1
cur = cur.next
if lastKth == 0:
head = head.next
if lastKth < 0:
cur = head
lastKth += 1
while lastKth != 0:
lastKth += 1
cur = cur.next
cur.next = cur.next.next
return head
if __name__ == "__main__":
head = Node(1)
node_2 = Node(2)
node_3 = Node(3)
node_4 = Node(4)
node_5 = Node(5)
node_6 = Node(6)
head.next = node_2
node_2.next = node_3
node_3.next = node_4
node_4.next = node_5
node_5.next = node_6
print("my linklist")
cur = head
while cur!=None:
print(cur.val)
cur = cur.next
solu = Solution()
lastKth = 4
solu.removeLastKthNode(head,lastKth)
print("Drop last "+str(lastKth)+" node")
cur = head
while cur != None:
print(cur.val)
cur = cur.next
双链表
class DoubleNode(object):
def __init__(self,x):
self.val = x
self.last = None
self.next = None
class Solution2(object):
def removeLastKthNode(self,head,lastKth):
if head == None or lastKth < 1:
return head
cur = head
while cur != None:
lastKth -= 1
cur = cur.next
if lastKth == 0:
head = head.next
head.last = None
if lastKth < 0:
cur = head
lastKth += 1
while lastKth != 0:
lastKth += 1
cur = cur.next
newNext = cur.next.next
cur.next = newNext
if newNext != None:
newNext.last = cur
return head
删除链表的中间节点和a/b处的节点
删除中间节点
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def removeMidNode(self,head):
if head == None or head.next == None:
return head
if head.next.next == None:
return head.next
pre = head
cur = head.next.next
while cur.next != None and cur.next.next != None:
pre = pre.next
cur = cur.next.next
pre.next = pre.next.next
return head
进阶
在这里插入代码片
反转单向和双向链表
单向链表
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def reverseList(self,head):
pre = None
while head != None:
next = head.next
head.next = pre
pre = head
head = next
return pre
if __name__ == "__main__":
solu = Solution()
head = Node(1)
node_2 = Node(2)
node_3 = Node(3)
node_4 = Node(4)
node_5 = Node(5)
head.next = node_2
node_2.next = node_3
node_3.next = node_4
node_4.next = node_5
cur = head
while cur != None:
print(cur.val)
cur = cur.next
print("reverse")
cur = solu.reverseList(head)
while cur != None:
print(cur.val)
cur = cur.next
双向链表
class DoubleNode(object):
def __init__(self,x):
self.val = x
self.last = None
self.next = None
class Solution2(object):
def reverseList(self,head):
pre = None
next = None
while head != None:
next = head.next
head.next = pre
head.last = next
pre = head
head = next
return pre
反转部分单向链表
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def reversePart(self,head,start,end):
len = 0
node_1 = head
start_pre = None
end_pos = None
# 找到开始之前和结束之后的位置
while node_1 != None:
len += 1
start_pre = node_1 if len == start - 1 else start_pre
end_pos = node_1 if len == end + 1 else end_pos
node_1 = node_1.next
if start > end or start < 1 or end > len :
return head
node_1 = head if start_pre == None else start_pre.next
node_2 = node_1.next
node_1.next = end_pos
while node_2 != end_pos :
next = node_2.next
node_2.next = node_1
node_1 = node_2
node_2 = next
if start_pre != None:
start_pre.next = node_1
return head
return node_1
if __name__ == "__main__":
head = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node5 = Node(5)
node6 = Node(6)
head.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
node5.next = node6
cur = head
while cur != None:
print(cur.val)
cur = cur.next
print("Part Reverse")
solu = Solution()
cur = solu.reversePart(head,2,4)
while cur != None:
print(cur.val)
cur = cur.next
环形单链表的约瑟夫环问题
原问题
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def josephusKill1(self,head,m):
if head == None or head.next == head or m < 1:
return head
last = head
while last.next != head:
last = last.next
count = 0
while head != last:
count += 1
if count == m:
last.next = head.next
count = 0
else:
last = last.next
head = last.next
return head
进阶
判断一个链表是否为回文结构
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def isPalindrome1(self,head):
stack = []
cur = head
len = 0
while cur != None:
stack.append(cur.val)
cur = cur.next
len += 1
if len % 2 != 0:
return False
half = len//2
i = 0
for i in range(0,half):
if stack[i] != stack[len-1-i]:
return False
i += 1
return True
if __name__ == "__main__":
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(3)
node5 = Node(2)
node6 = Node(1)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
node5.next = node6
cur = node1
while cur != None:
print(cur.val)
cur = cur.next
solu = Solution()
print(solu.isPalindrome1(head=node1))
进阶
def isPalindrome2(self,head):
if head == None or head.next == None:
return True
right = head.next
cur = head
while cur.next != None and cur.next.next != None:
right = right.next
cur = cur.next.next
stack2 = []
while right != None:
stack2.append(right.val)
right = right.next
print(stack2)
while len(stack2) != 0:
if head.val != stack2.pop():
return False
head = head.next
return True
将单向链表按某值划分成左边小、中间相同、右边大的形式
原问题
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def listPartition1(self,head,pivot):
if head == None:
return head
cur = head
i = 0
while cur != None:
i += 1
cur = cur.next
nodeArr = [None]*i
cur = head
for i in range(0,len(nodeArr)):
nodeArr[i] = cur
cur = cur.next
self.arrPartition(nodeArr,pivot)
for i in range(1,len(nodeArr)):
nodeArr[i-1].next = nodeArr[i]
nodeArr[i-1].next =None
return nodeArr[0]
def arrPartition(self,nodeArr,pivot):
small = -1
big = len(nodeArr)
index = 0
while index != big:
if nodeArr[index].val < pivot:
small += 1
self.swap(nodeArr,small,index)
index += 1
elif nodeArr[index].val == pivot:
index += 1
else:
big -= 1
self.swap(nodeArr,big,index)
def swap(self,nodeArr,a,b):
nodeArr[a],nodeArr[b] = nodeArr[b],nodeArr[a]
if __name__ == "__main__":
node1 = Node(9)
node2 = Node(0)
node3 = Node(4)
node4 = Node(5)
node5 = Node(1)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
cur = node1
while cur != None:
print(cur.val)
cur = cur.next
print("partation:")
solu = Solution()
head = solu.listPartition1(node1,2)
while head != None:
print(head.val)
head = head.next
进阶
class Solution2(object):
def listPartition2(self,head,pivot):
sH = None #小的头
sT = None #小的尾
eH = None #相等的头
eT = None #相等的尾
bH = None #大的头
bT = None #大的尾
next = None #保存下一个节点
#所有的节点分进三个链表中
while head != None:
next = head.next
head.next = None
if head.val < pivot:
if sH == None:
sH = head
sT = head
else:
sT.next = head
sT = head
elif head.val == pivot:
if eH == None:
eH = head
eT = head
else:
eT.next = head
eT = head
else:
if bH == None:
bH = head
bT = head
else:
bT.next = head
bT = head
head = next
#小的和相等的重新连接
if sT != None:
sT.next = eH
eT = sT if eT == None else eT
#所有的重新连接
if eT != None:
eT.next = bH
if sH != None:
return sH
elif eH != None:
return eH
else:
return bH
复制含有随机指针节点的链表
原问题
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
self.rand = None
class Solution(object):
def copyListWithRand1(self,head):
map = {}
cur = head
while cur != None:
map[cur].next = map[cur.next]
map[cur].rand = map[cur.rand]
cur = cur.next
return map[head]
进阶
def copyListWithRand2(self,head):
if head == None:
return None
cur = head
#复制并连接每个节点
while cur != None:
next = cur.next
cur.next = Node(cur.val)
cur.next.next = next
cur = next
cur = head
curCopy = None
#设置复制节点的rand指针
while cur != None:
next = cur.next.next
curCopy = cur.next
curCopy.rand = cur.rand.next if cur.rand != None else None
cur = next
res = head.next
cur = head
#拆分
while cur != None:
next = cur.next.next
curCopy = cur.next
cur.next = cur
curCopy.next = next.next if next != None else None
cur = next
return res
两个单链表生成相加链表
方法一:利用栈
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def addList1(self,head1,head2):
s1 = []
s2 = []
while head1 != None:
s1.append(head1.val)
head1 = head1.next
while head2 != None:
s2.append(head2.val)
head2 = head2.next
ca,n1,n2,n = 0,0,0,0
node = None
pre = None
while len(s1) != 0 or len(s2) != 0:
n1 = 0 if len(s1) == 0 else s1.pop()
n2 = 0 if len(s2) == 0 else s2.pop()
n = n1+n2+ca
pre = node
node = Node(n%10)
node.next = pre
ca = n / 10
if ca == 1:
pre = node
node = Node(1)
node.next = pre
return node
方法二:利用逆序
class Solution2(object):
def addList2(self,head1,head2):
head1 = self.reverseList(head1)
head2 = self.reverseList(head2)
ca,n1,n2,n = 0,0,0,0
c1 = head1
c2 = head2
node = None
pre = None
while c1 != None or c2 != None:
n1 = c1.val if c1 != None else 0
n2 = c2.val if c2 != None else 0
n = n1+n2+ca
pre = node
node = Node(n%10)
node.next = pre
ca = n / 10
c1 = c1.next if c1 != None else None
c2 = c2.next if c2 != None else None
if ca == 1:
pre = node
node = Node(1)
node.next = pre
self.reverseList(head1)
self.reverseList(head2)
return node
def reverseList(self,head):
pre = None
next = None
while head != None:
next = head.next
head.next = pre
pre = head
head = next
return pre
两个单链表相交的一系列问题
判断是否有环,并返回该节点
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def getLoopNode(self,head):
if head == None or head.next == None or head.next.next == None:
return None
slow = head.next
fast = head.next.next
while slow != fast:
if fast.next == None or fast.next.next == None:
return None
fast = fast.next.next
slow = slow.next
#找到head
fast = head
while slow != fast:
slow = slow.next
fast = fast.next
return slow
if __name__ == "__main__":
#测试
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node5 = Node(5)
node6 = Node(6)
node7 = Node(7)
node8 = Node(9)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
node5.next = node6
node6.next = node7
node7.next = node8
node8.next = node3
cur = node1
#while cur != None:
#print(cur.val)
#cur = cur.next
solu = Solution()
print(solu.getLoopNode(cur).val)
两个无环链表是否相交
def noLoop(self,head1,head2):
if head1 == Node or head2 == None:
return None
cur1 = head1
cur2 = head2
n = 0
while cur1.next != None:
n += 1
cur1 = cur1.next
while cur2.next != None:
n -= 1
cur2 = cur2.next
if cur1 != cur2:
return None
cur1 = head1 if n > 0 else head2
cur2 = head2 if cur1 == head1 else head1
n = abs(n)
while n != 0:
n -= 1
cur1 = cur1.next
while cur1 != cur2:
cur1 = cur1.next
cur2 = cur2.next
return cur1
判断两个有环链表是否相交,返回第一个相交节点
def bothLoop(self,head1,loop1,head2,loop2):
cur1 = None
cur2 = None
if loop1 == loop2:
cur1 = head1
cur2 = head2
n = 0
while cur1 != loop1:
n += 1
cur1 = cur1.next
while cur2 != loop2:
n -= 1
cur2 = cur2.next
cur1 = head1 if n > 0 else head2
cur2 = head2 if cur1 == head1 else head1
n = abs(n)
while n != 0:
n -= 1
cur1 = cur1.next
while cur1 != cur2:
cur1 = cur1.next
cur2 = cur2.next
return cur1
else:
cur1 = loop1.next
while cur1 != loop1:
if cur1 == loop2:
return loop1
cur1 = cur1.next
return None
主题干
def getIntersectNode(self,head1,head2):
if head1 == None or head2 == None:
return None
loop1 = self.getLoopNode(head1)
loop2 = self.getLoopNode(head2)
if loop1 == None and loop2 == None:
return self.noLoop(head1,head2)
if loop1 != None and loop2 != None:
return self.bothLoop(head1,loop1,head2,loop2)
return None
将单链表的每K个节点之间逆序
方法一:利用栈结构的解法
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def reverseKNodes1(self,head,K):
if K < 2:
return head
stack = []
newHead = head
cur = head
pre = None
while cur != None:
next = cur.next
stack.append(cur)
if len(stack) == K:
pre = self.resign1(stack,pre,next)
newHead = cur if newHead == head else newHead
cur = next
return newHead
def resign1(self,stack,left,right):
cur = stack.pop()
if left != None:
left.next = cur
while len(stack) != 0:
next = stack.pop()
cur.next = next
cur = next
cur.next = right
return cur
if __name__ == "__main__":
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node5 = Node(5)
node6 = Node(6)
node7 = Node(7)
node8 = Node(8)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
node5.next = node6
node6.next = node7
node7.next = node8
node8.next = None
cur = node1
while cur != None:
print(cur.val)
cur = cur.next
print("将单链表的每K个节点之间逆序")
solu = Solution()
newH = solu.reverseKNodes1(node1,3)
print(newH.val)
cur_new = newH
while cur_new != None:
print(cur_new.val)
cur_new = cur_new.next
方法二:不需要栈结构,在原链表中直接调整
class Solution2(object):
def reverseKNodes2(self,head,K):
if K < 2:
return head
cur = head
start = None
pre = None
count = 1
while cur != None:
next = cur.next
if count == K:
start = head if pre == None else pre.next
head = cur if pre == None else head
self.resign2(pre,start,cur,next)
pre =start
count = 0
count += 1
cur = next
return head
def resign2(self,left,start,end,right):
pre = start
cur = start.next
while cur != right:
next = cur.next
cur.next = pre
pre = cur
cur = next
if left != None:
left.next = end
start.next = right
删除无序链表中值重复出现的节点
方法一:利用哈希表
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def removeRep1(self,head):
if head == None:
return None
vals = set()
pre = head
cur = head.next
vals.add(head.val)
while cur != None:
if cur.val in vals:
pre.next = cur.next
else:
vals.add(cur.val)
pre = cur
cur = cur.next
类似于选择排序过程
class Solution(object):
def removeRep2(self,head):
cur = head
while cur != None:
pre = cur
next = cur.next
while next != None:
if cur.val == next.val:
pre.next = next.next
else:
pre = next
next = next.next
cur = cur.next
在单链表中删除指定值的节点
方法一:利用栈等容器类
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def removeValue1(self,head,num):
stack = []
while head != None:
if head.val != num:
stack.append(head)
head = head.next
while len(stack) != 0:
stack[-1].next = head
head = stack.pop()
return head
方法二:不用任何容器类
class Solution(object):
def removeValue2(self,head,num):
while head != None:
if head.val != num:
break
head = head.next
pre = head
cur = head
while cur != None:
if cur.val == num:
pre.next = cur.next
else:
pre = cur
cur = cur.next
return head
将搜索二叉树转换成双向链表
方法一:队列+二叉树中序遍历
class Node(object):
def __init__(self,x):
self.val = x
self.left = None
self.right = None
class Solution(object):
def convert1(self,head):
queue = []
self.inOrderToQueue(head,queue)
if len(queue) == 0:
return head
head = queue.pop(0)
pre = head
pre.left = None
while len(queue) != 0:
cur = queue.pop(0)
pre.right = cur
cur.left = pre
pre = cur
pre.right = None
return = head
def inOrderToQueue(self,head,queue):
if head == None:
return
self.inOrderToQueue(head.left,queue)
queue.append(head)
self.inOrderToQueue(head.right,queue)
方法二:递归
单链表的选择排序
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def selectionSort(self,head):
tail = None#排序部分尾部
cur = head#未排序部分头部
smallPre = None#最小节点的前一个节点
small = None#最小的节点
while cur != None:
small = cur
smallPre = self.getSmallestPreNode(cur)
if smallPre != None:
small = smallPre.next
smallPre.next = small.next
cur = cur.next if cur == small else cur
if tail == None:
head = small
else:
tail.next = small
tail = small
return head
def getSmallestPreNode(self,head):
smallPre = None
small = head
pre = head
cur = head.next
while cur != None:
if cur.val < small.val:
smallPre = pre
small = cur
pre = cur
cur = cur.next
return smallPre
if __name__ == "__main__":
solu = Solution()
node1 = Node(10)
node2 = Node(2)
node3 = Node(8)
node4 = Node(1)
node5 = Node(3)
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
cur = node1
while cur != None:
print(cur.val)
cur = cur.next
print("排序之后:")
solu = Solution()
cur_new = solu.selectionSort(node1)
while cur_new != None:
print(cur_new.val)
cur_new = cur_new.next
一种怪异的节点删除方式
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def removeNodeWired(self,node):
if node == None:
return
next = node.next
if next == None:
raise Exception("can not remove last node.")
node.val = next.val
node.next = next.next
向有序的环形单链表中插入新节点
class Node(object):
def __init__(self,x):
self.val = x
self.next =None
class Solution(object):
def insertNum(self,head,num):
node = Node(num)
if head == None:
node.next = node
return node
pre = head
cur = head.next
while cur != head:
if pre.val <= num and cur.val >= num:
break
pre = cur
cur = cur.next
pre.next = node
node.next =cur
return head if head.val < num else node
合并两个有序的单链表
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def merge(self,head1,head2):
if head1 == None or head2 == None:
if head1 != None:
return head1
else:
return head2
if head1.val < head2.val:
head = head1
else:
head = head2
cur1 = head1 if head == head1 else head2
cur2 = head2 if head == head1 else head1
pre = None
while cur1 != None and cur2 != None:
if cur1.val <= cur2.val:
pre = cur1
cur1 = cur1.next
else:
next = cur2.next
pre.next = cur2
cur2.next = cur1
pre = cur2
cur2 = next
pre.next = cur2 if cur1 == None else cur1
return head
按照左右半区的方式重新组合单链表
class Node(object):
def __init__(self,x):
self.val = x
self.next = None
class Solution(object):
def relocate(self,head):
if head == None or head.next == None:
return
mid = head
right = head.next
while right.next != None and right.next.next != None:
mid = mid.next
right = right.next.next
right = mid.next
mid.next = None
self.mergeLR(head,right)
def mergeLR(self,left,right):
next = None
while left.next != None:
next = right.next
right.next = left.next
left.next = right
left = right.next
right = next
left.next = right