目录
61.二叉搜索树的第K个节点
给定一棵二叉搜索树,请找出其中的第k小的结点。例如,(6,3,8,2,5,7,9)中,按结点数值大
小顺序第三小结点的值为5。
给定二叉树:
6
/ \
3 8
/ \ / \
2 5 7 9
思路:二插搜索树的中序遍历节点为排序数组,中序遍历节点,直接返回第k个数即可
class TreeNode:
def __init__(self,val):
self.val=val
self.left=None
self.right=None
class Solution:
def __init__(self):
self.res=[]
def findTreeKthNode(self,root,k):
if root==None:
return -1
self.searchTree(root)
if k<0 or k>len(self.res):
return -1
return self.res[k-1]
def searchTree(self,root):
if root ==None:
return
self.searchTree(root.left)
self.res.append(root.val)
self.searchTree(root.right)
a = TreeNode(6)
b = TreeNode(3)
c=TreeNode(2)
d = TreeNode(8)
e = TreeNode(7)
f = TreeNode(9)
g=TreeNode(5)
a.left, a.right = b, d
d.left, d.right = e,f
b.left,b.right =c,g
s=Solution()
res = s.findTreeKthNode(a,2)
print(res)
62.滑动窗口的最大值
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组
{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]}。
思路:将数组分片为len(a)-size+1个窗口,依次取最大值
class Solution:
def maxValOfWindows(self,a,size):
if size>len(a):
return None
res=[]
for i in range(len(a)-size+1):
res.append(max(a[i:min(i+size,len(a))]))
return res
a=[2,3,4,2,6,2,5,1]
s=Solution()
r=s.maxValOfWindows(a,3)
print(r)
63.序列化和反序列化二叉树
请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。
序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,
序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
思路:序列化:先序遍历树,以!分割树中节点的值,连接树中值为字符串
反序列化 :以!分割字符串,得到数的值列表;先序遍历构建二叉树
class TreeNode(object):
def __init__(self, val):
self.val = val
self.left = None
self.right = None
def serialize(root):
if root is None:
return "#!"
return str(root.val)+'!' + serialize(root.left) + serialize(root.right)
def deserialize(s):
#vals = list(s)
vals = s.split('!')
print(vals)
def build():
if vals:
val = vals.pop(0)
if val == '#':
return None
root = TreeNode(int(val))
root.left = build()
root.right = build()
return root
return build()
def bfs(root):
if root is None:
return None
queue = [root]
while queue:
pop_node = queue.pop(0)
print(pop_node.val)
if pop_node.left is not None:
queue.append(pop_node.left)
if pop_node.right is not None:
queue.append(pop_node.right)
a = TreeNode(1)
b = TreeNode(2)
c = TreeNode(3)
d = TreeNode(4)
e = TreeNode(5)
f = TreeNode(6)
g = TreeNode(7)
a.left, a.right = b, c
b.left, b.right = d, e
c.left, c.right = f, g
res = serialize(a)
print(res)
root = deserialize(res)
bfs(root)
64.数据流中的中位数
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。
如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
思路:
1、insert()方法读取数据流,获取排序数组
2、使用GetMedian()方法获取当前读取数据的中位数。
class Solution:
def __init__(self):
self.data = []
def insert(self, num):
if not self.data:
self.data.append(num)
elif num > self.data[-1]:
self.data.append(num)
else:
for i in range(len(self.data)):
if self.data[i] > num:
self.data = self.data[:i] + [num] + self.data[i:]
break
def getMedian(self):
length = len(self.data)
if length % 2:
return float(self.data[length // 2])
return float((self.data[length // 2] + self.data[length // 2 - 1]) / 2)
s = Solution()
for item in [5, 2, 3, 4, 1, 6, 7, 0, 8]:
s.insert(item)
print(s.getMedian())
65.矩阵中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中
的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了
矩阵中的某一个格子,则之后不能再次进入这个格子。 例如,在下面的3 X 4 矩阵中包含一条字符
串"bfce"的路径,但是矩阵中不包含"abfb"路径,因为字符串的第一个字符b占据了矩阵中的第一行
第二个格子之后,路径不能再次进入该格子。
a b t g
c f c s
j d e h
思路:回溯法,1、遍历所有格子找到路口;2、上下左右移动寻找与当前字符相等的位置,mask记录访问过
的位置
class Solution:
def findPath(self,a,s):
index=0 #当前s的下标
for i in range(len(a)):
for j in range(len(a[0])):
mask=[[True]*len(a[0]) for i in range(len(a))]
if self.dfs(a,s,mask,i,j,index):
return True
return False
def dfs(self,a,s,mask,i,j,index):
if(index==len(s)):
return True
if (0<=i<len(a) and 0<=j<=len(a[0]) and mask[i][j] and a[i][j]==s[index]):
mask[i][j]=False
return self.dfs(a,s,mask,i+1,j,index+1) or self.dfs(a,s,mask,i-1,j,index+1) or self.dfs(a,s,mask,i,j-1,index+1) or self.dfs(a,s,mask,i,j+1,index+1)
return False
a=[list('abtg'),list('cfcs'),list('jdeh')]
s1="bfce"
s2="abfb"
s=Solution()
r=s.findPath(a,s1)
r2=s.findPath(a,s2)
print(r,r2)
66.机器人的运动范围
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方
向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入
方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问
该机器人能够达到多少个格子?
思路:回溯法,1、从(0,0)开始遍历矩阵,上下左右移动探索满足条件行坐标和列坐标的数位之和大于k的格子,mask记录访问过格子,全局计数+1
class Solution:
def __init__(self):
self.num=0
def calSumBit(self,i,j):
r= sum(list(map(int,str(i))))+sum(list(map(int,str(j))))
return r
def dfs(self,a,k,mask,i,j):
if(0<=i<len(a) and 0<=j<len(a[0]) and mask[i][j] and self.calSumBit(i,j)<=k):
mask[i][j]=False
self.num+=1
self.dfs(a,k,mask,i-1,j)
self.dfs(a,k,mask,i+1,j)
self.dfs(a,k,mask,i,j-1)
self.dfs(a,k,mask,i,j+1)
def findWay(self,a,k,i,j):
mask=[[True]*len(a[0]) for i in range(len(a))]
self.dfs(a,k,mask,i,j)
return self.num
s=Solution()
a=[[0]*6 for i in range(7)] #7*6二维数组
k=6
r=s.findWay(a,k,0,0)
print(r)
67、剪绳子
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],...,k[m]。
请问k[0]xk[1]x...xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
思路1:动态规划:f[n]=max(f[n-i]*f[i]) f[n]记录长度为n的绳子最大乘积
思路2:贪婪算法:当n>5时; 2*(n-2)>n 3*(n-3)>n 3*(n-3)>2(n-2) 每次尽可能剪成长度为3的绳子;其次剪为2的绳子
def cut_rope(length):
if length < 2: return 0
if length == 2: return 1
if length == 3: return 2
# 其他情况,如果总的绳子长度=4,那么效果一样,最大乘积都是4
# 如果绳子长度>=5,那么需要尽可能的多剪成长度为3的子绳子段,然后长度为2的绳子最多2段,不要留绳子长度为1的
timesOf3 = length // 3
if (length - timesOf3 * 3) == 1: # length=4,7,10,如果是10=3*3*3*1或者3*()
timesOf3 -= 1
timeOf2 = (length - timesOf3 * 3) // 2
result = pow(3, timesOf3) * pow(2, timeOf2)
return result