剑指offer-题目-思路-python实现61-67

目录

61.二叉搜索树的第K个节点

62.滑动窗口的最大值

63.序列化和反序列化二叉树

64.数据流中的中位数

65.矩阵中的路径

66.机器人的运动范围

67、剪绳子


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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值