回溯法
67 机器人的运动范围
题目描述
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
解题思路
- 设置visited矩阵记录每一个格子的访问状态。访问过设置为1,为访问过设置0.
- 递归实现回溯。依次访问当前位置的上下左右的格子。
# -*- coding:utf-8 -*-
import sys
class Solution:
def movingCount(self, threshold, rows, cols):
# write code here
# 记录每个格子的状态
if rows < 0 and cols < 0:
return False
visited = [0] * (rows * cols)
count = self.calCount(threshold, rows, cols, 0, 0, visited)
return count
def calCount(self, threshold, rows, cols, row, col, visited):
count = 0
if self.check(threshold, rows, cols, row, col, visited):
visited[row * cols + col] = True
count = 1 + self.calCount(threshold, rows, cols, row-1, col, visited) \
+ self.calCount(threshold, rows, cols, row+1, col, visited) \
+ self.calCount(threshold, rows, cols, row, col+1, visited) \
+ self.calCount(threshold, rows, cols, row, col-1, visited)
return count
def check(self, threshold, rows, cols, row, col, visited):
if 0 <= row < rows and 0 <= col < cols and visited[row * cols + col] == 0 \
and self.getSum(row) + self.getSum(col) <= threshold:
return True
return False
def getSum(self, digit):
res = 0
while digit > 0:
res += digit % 10
digit //= 10
return res
if __name__ == '__main__':
arr = sys.stdin.readline().strip().split(' ')
threshold, rows, cols = [int(x) for x in arr]
count = Solution().movingCount(threshold, rows, cols)
print(count)
66 矩阵中的路径
题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
解题思路
- 设置visited矩阵记录每一个格子的访问状态。访问过设置为1,为访问过设置0.
- index 记录path的元素, 回溯法寻找匹配的元素。如果当前元素符合,寻找当前元素的四周元素。
- 如果没有找到, index-1回溯到前一个位置。
# -*- coding:utf-8 -*-
class Solution:
def hasPath(self, matrix, rows, cols, path):
# write code here
if matrix is None and rows <= 0 and cols <= 0:
return False
visited = [0] * (rows * cols)
pathindex = 0
for row in range(rows):
for col in range(cols):
if self.hasPathCore(matrix, rows, cols, row, col, path, pathindex, visited):
return True
return False
def hasPathCore(self, matrix, rows, cols, row, col, path, pathindex, visited):
haspath = False
length = len(path)
if pathindex == length:
return True
if rows > row >= 0 and cols > col >= 0 and visited[row * cols + col] == 0 \
and matrix[row * cols + col] == path[pathindex]:
pathindex += 1
visited[row * cols + col] = 1
haspath = self.hasPathCore(matrix, rows, cols, row - 1, col, path, pathindex, visited) or \
self.hasPathCore(matrix, rows, cols, row + 1, col, path, pathindex, visited) or \
self.hasPathCore(matrix, rows, cols, row, col - 1, path, pathindex, visited) or \
self.hasPathCore(matrix, rows, cols, row, col + 1, path, pathindex, visited)
if not haspath:
pathindex -= 1
visited[row * cols + col] = 0
return haspath
栈和队列
65 滑动窗口的最大值
题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
解题思路
- 设置一个两头都能进出的数据结构,python里边的list符合。
- 存储元素的下标而非元素值,目的是好判断是否在窗口中。与当前元素下标差值大于size的都应该滑出窗口。
- 判断当前元素和栈内元素的大小,大于栈尾部元素,尾部元素出栈。
class Solution:
def maxInWindows(self, num, size):
# write code here
if num is None or size <= 0:
return []
dequeen = []
windows = []
for idx, val in enumerate(num):
if dequeen is []:
dequeen.append(idx)
if idx - dequeen[0] >= size:
dequeen.pop(0)
while dequeen is not [] and val >= num[dequeen[-1]]:
dequeen.pop()
dequeen.append(idx)
if idx >= size - 1:
windows.append(num[dequeen[0]])
return windows
21 包含min函数的栈
#########################################################################
# 21 包含min函数的栈
#########################################################################
# 另外用一个辅助栈存储最小的元素
# 注意判断栈是否为空
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.stack = []
self.min_stack = []
def push(self, node):
self.stack.append(node)
if self.min_stack == []:
self.min_stack.append(node)
else:
self.min_stack.append(min(node, self.min_stack[-1]))
def pop(self):
if self.stack != [] and self.min_stack != []:
self.min_stack.pop()
return self.stack.pop()
def top(self):
if self.stack != []:
return self.stack[-1]
def min(self):
if self.min_stack != []:
return self.min_stack[-1]
22 栈的压入和弹出序列
#########################################################################
# 22 栈的压入和弹出序列
#########################################################################
# 利用辅助栈,判断辅助栈最后能否全部弹出
# -*- coding:utf-8 -*-
class Solution:
def IsPopOrder(self, pushV, popV):
# write code here
if pushV == None and popV == None:
return True
if pushV == None or popV == None:
return False
stack = []
for val in pushV:
stack.append(val)
while stack != [] and stack[-1] == popV[0]:
stack.pop()
popV.pop(0)
return True if stack == [] else False
二叉树
58 二叉树的下一个结点
题目描述
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
解题思路
- 中序遍历是左根右。
- 如果这个结点有右子树,下一个结点就是右子树的最左结点。
- 如果这个结点没有右子树,父节点存在,是父节点的左子结点,那么下一个结点就是此父节点,
- 如果不是父节点的左子节点,向上遍历找到一个结点是它父节点的左子节点,此节点的父节点就是下一个结点。
class Solution:
def GetNext(self, pNode):
# write code here
if pNode == None:
return None
if pNode.right:
right = pNode.right
while right.left != None:
right = right.left
return right
elif pNode.next != None:
parent = pNode.next
if pNode == parent.left:
return parent
else:
curNode = pNode
while parent != None and curNode == parent.right:
curNode = parent
parent = parent.next
return parent
return None
59 对称二叉树
题目描述
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
解题思路
前序遍历: 根左右
自定义反前序遍历: 根右左
只要两个遍历结果一样,就是对称二叉树。也就是两个树,根节点相等,root1的左子树与oot2 的右子树对称,root1的右子树与oot2 的左子树对称,结果就是True
class Solution:
def isSymmetrical(self, pRoot):
# write code here
return self.isSymmetricalCore(pRoot, pRoot)
def isSymmetricalCore(self, root1, root2):
if root1 == None and root2 == None:
return True
if root1 == None or root2 == None:
return False
if root1.val != root2.val:
return False
return self.isSymmetricalCore(root1.left, root2.right) and \
self.isSymmetricalCore(root1.right, root2.left)
60 二叉树打印多行
题目描述
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
解题思路
层次遍历,另开一个存储空间存储每一层的数值。
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回二维列表[[1,2],[4,5]]
def Print(self, pRoot):
# write code here
if pRoot == None:
return []
res = []
queen = [pRoot]
while queen:
cur = []
size = len(queen)
for _ in range(size):
root = queen.pop(0)
cur.append(root.val)
if root.left:
queen.append(root.left)
if root.right:
queen.append(root.right)
res.append(cur)
return res
61 之字形打印二叉树
题目描述
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
解题思路
定义两个栈,当前位置是奇数层时,先存储当前结点的左结点在存右结点到另一个栈中。偶数层时相反。
class Solution:
def Print(self, pRoot):
# write code here
if pRoot == None:
return []
stack_odd = []
stack_even = []
res = []
stack_odd.append(pRoot)
while stack_odd or stack_even:
cur = []
while stack_odd:
root = stack_odd.pop()
cur.append(root.val)
if root.left:
stack_even.append(root.left)
if root.right:
stack_even.append(root.right)
if cur:
res.append(cur)
cur = []
while stack_even:
root = stack_even.pop()
cur.append(root.val)
if root.right:
stack_odd.append(root.right)
if root.left:
stack_odd.append(root.left)
if cur:
res.append(cur)
return res
62 序列化二叉树
题目描述
请实现两个函数,分别用来序列化和反序列化二叉树
解题思路
前序遍历序列化,将空值记录成特殊的符号。
class Solution:
def Serialize(self, root):
# write code here
if root == None:
return "#"
return str(root.val) + ',' + self.Serialize(root.left) + ',' + self.Serialize(root.right)
def Deserialize(self, s):
# write code here
lis = s.split(',')
return self.DeserializeTree(lis)
def DeserializeTree(self, lis):
if lis == []:
return None
val = lis.pop(0)
root = None
if val != '#':
root = TreeNode(int(val))
root.left = self.DeserializeTree(lis)
root.right = self.DeserializeTree(lis)
return root
63 二叉搜索树的第K个结点
#########################################################################
# 63 二叉搜索树的第K个结点
#########################################################################
# 中序遍历 返回第K个
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回对应节点TreeNode
def KthNode(self, pRoot, k):
# write code here
if pRoot == None:
return None
stack = []
res = []
cur = pRoot
while stack or cur:
while cur:
stack.append(cur)
cur = cur.left
cur = stack.pop()
res.append(cur)
cur = cur.right
print(len(res))
if len(res) == k:
return res[k-1]
if k > len(res):
return None
50 二叉树的最低公共祖先
#########################################################################
# 50 二叉树的最低公共祖先
#########################################################################
# (1)二叉搜索树的最低公共祖先
# 判断结点是与根结点的大小关系,都小于根就递归搜索左子树, 找到返回。
# 如果都大于根就递归右子树, 找到返回结点
# 如果不满足上述两个条件,返回根节点
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
if root == None:
return None
if root != None and root == p or root == q:
return root
if root.val > p.val and root.val > q.val:</