题1:重建二叉树
题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路:
- 重建二叉树返回的结果是依次打印出二叉树的根节点,肯定要用到递归的思想
- 先根据前序list找到根节点以及其索引
- 然后在前序和中序list中定位到新的子树的前序和中序list
- 循环终止的条件就是看前序的list是否为空,是否元素为1!
代码:
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
# 首先根据前序第一个元素作为根节点!
# 然后根据这个元素将中序的序列变为两部分!
if len(pre)==0:
return None
elif len(pre)==1: # 如果只有1个元素的时候 tin为空 所以取不到索引 单独拿出来!
return TreeNode(pre[0])
else:
root=TreeNode(pre[0])
val=tin.index(pre[0])
root.left=self.reConstructBinaryTree(pre[1:val+1],tin[:val])
root.right=self.reConstructBinaryTree(pre[val+1:],tin[val+1:])
return root
但是上述还是有点绕,我们来进行拆解:
- 第一步返回1
def reConstructBinaryTree(self, pre, tin):
'''
传入:
pre = [1,2,4,7,3,5,6,8]
tin = [4,7,2,1,5,3,8,6]
'''
# pre表示前序序列 tin表示中序序列
# 首先根据前序第一个元素作为根节点!
# 然后根据这个元素将中序的序列变为两部分!
if len(pre)==0:
return None
elif len(pre)==1: # 如果只有1个元素的时候 tin为空 所以取不到索引 单独拿出来!
return TreeNode(pre[0])
else:
root=TreeNode(pre[0]) # 根节点为前序第一个元素 root = 1
val=tin.index(pre[0]) # 返回根节点元素对应的索引 val = 3
root.left=self.reConstructBinaryTree(pre[1:val+1],tin[:val]) # 这时候树的左子节点为中序中索引的前半部分
root.right=self.reConstructBinaryTree(pre[val+1:],tin[val+1:])
'''
root.left=self.reConstructBinaryTree(pre=[2,4,7],tin=[4,7,2])
root.right=self.reConstructBinaryTree(pre=[3,5,6,8],tin=[5,3,8,6])
'''
return root # 返回1
- 第二步返回2
def reConstructBinaryTree(self, pre, tin):
'''
传入:
pre = [2,4,7]
tin = [4,7,2]
'''
# pre表示前序序列 tin表示中序序列
# 首先根据前序第一个元素作为根节点!
# 然后根据这个元素将中序的序列变为两部分!
if len(pre)==0:
return None
elif len(pre)==1: # 如果只有1个元素的时候 tin为空 所以取不到索引 单独拿出来!
return TreeNode(pre[0])
else:
root=TreeNode(pre[0]) # 根节点为前序第一个元素 root = 2
val=tin.index(pre[0]) # 返回根节点元素对应的索引 val = 2
root.left=self.reConstructBinaryTree(pre[1:val+1],tin[:val]) # 这时候树的左子节点为中序中索引的前半部分
root.right=self.reConstructBinaryTree(pre[val+1:],tin[val+1:])
'''
root.left=self.reConstructBinaryTree(pre=[4,7],tin=[4,7])
root.right=self.reConstructBinaryTree(pre=[3,5,6,8],tin=[5,3,8,6])
'''
return root # 返回2
- 第三步返回4
def reConstructBinaryTree(self, pre, tin):
'''
传入:
pre = [4,7]
tin = [4,7]
'''
# pre表示前序序列 tin表示中序序列
# 首先根据前序第一个元素作为根节点!
# 然后根据这个元素将中序的序列变为两部分!
if len(pre)==0:
return None
elif len(pre)==1: # 如果只有1个元素的时候 tin为空 所以取不到索引 单独拿出来!
return TreeNode(pre[0])
else:
root=TreeNode(pre[0]) # 根节点为前序第一个元素 root = 4
val=tin.index(pre[0]) # 返回根节点元素对应的索引 val = 0
root.left=self.reConstructBinaryTree(pre[1:val+1],tin[:val]) # 这时候树的左子节点为中序中索引的前半部分
root.right=self.reConstructBinaryTree(pre[val+1:],tin[val+1:])
'''
root.left=self.reConstructBinaryTree(pre=[7],tin=[])
root.right=self.reConstructBinaryTree(pre=[3,5,6,8],tin=[5,3,8,6])
'''
return root # 返回4
- 第四步返回7
def reConstructBinaryTree(self, pre, tin):
'''
传入:
pre = [7]
tin = []
'''
# pre表示前序序列 tin表示中序序列
# 首先根据前序第一个元素作为根节点!
# 然后根据这个元素将中序的序列变为两部分!
if len(pre)==0:
return None
elif len(pre)==1: # 如果只有1个元素的时候 tin为空 所以取不到索引 单独拿出来!
return TreeNode(pre[0]) # 返回7了
else:
root=TreeNode(pre[0]) # 根节点为前序第一个元素 root = 4
val=tin.index(pre[0]) # 返回根节点元素对应的索引 val = 0
root.left=self.reConstructBinaryTree(pre[1:val+1],tin[:val]) # 这时候树的左子节点为中序中索引的前半部分
root.right=self.reConstructBinaryTree(pre[val+1:],tin[val+1:])
'''
root.left=self.reConstructBinaryTree(pre=[7],tin=[])
root.right=self.reConstructBinaryTree(pre=[3,5,6,8],tin=[5,3,8,6])
'''
return root
后续同理,就不一一展示。
题2:旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
代码1:直接min函数开挂…
# -*- coding:utf-8 -*-
class Solution:
def minNumberInRotateArray(self, rotateArray):
# write code here
if len(rotateArray) == 0:
return 0
else:
return min(rotateArray)
代码2:采用二分查找的思路!
但下述代码在牛客上是通过不了,LeetCode是可以的。。。说时间超出了!
# -*- coding:utf-8 -*-
class Solution:
def minNumberInRotateArray(self, rotateArray):
# write code here
# 采用二分查找
l, r = 0, len(rotateArray)-1 # 设两个指针
while l <= r:
mid = (l + r) // 2
if rotateArray[l] < mid:
# 如果左指针小于中值 则移动左指针
l = mid
elif rotateArray[r] > mid:
# 如果右指针大于中值 则移动右指针
r = mid
else:
return rotateArray[r]
思路:运用图形的方式 大概分为以下几步:
题3 求1+2+3+…+n
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
代码1:直接使用sum + range
# -*- coding:utf-8 -*-
class Solution:
def Sum_Solution(self, n):
# write code here
return sum(range(1,n+1))
代码2:终止递归采用逻辑与的短路特性
# -*- coding:utf-8 -*-
class Solution:
def Sum_Solution(self, n):
# write code here
return n and n + self.Sum_Solution(n-1)
题4:跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
思路:
- 其实就是求多少个1和多少个2求和加起来等于n,顺序一模一样才算相同的跳法,否则两次。
- 递归?怎么递归?
- 很朴素的想法,设一个list=[1,2] 然后每次从里面随机选一个数,一直加起来等于n 但是问题是这只是一种跳法,另外什么时候循环终止呢?都是问题!
- 简单试验了一下:
- 1级台阶:1种跳法
- 2级台阶:2种跳法
- 3级台阶:3种跳法
- 4级台阶:5种跳法
- 5级台阶:8种跳法
- 咦,貌似发现了规律,就是符合斐波那契数列!那为什么是这样呢?先不管!首先写代码!
# -*- coding:utf-8 -*-
class Solution:
def jumpFloor(self, number):
# write code here
# 注意边界条件
if number <= 0:
return 0
alist = [1,2]
if number == 1:
return 1
elif number == 2:
return 2
else:
for i in range(2, number):
alist.append(alist[i-1] + alist[i-2])
return alist[number-1]
那为什么会是斐波那契数列呢?
- 首先我们考虑最简单的情况。如果只有1级台阶,那么显然只一种跳法。如果有2级台阶,那就有两种跳法:一种是分两次跳,每次跳1级;另一种是一次跳2级。这个没问题 上面就是这么做的!
- 接着,我们来讨论一般情况。我们把n级台阶时的跳法看成是n的函数,记为f(n)。当n>2时,第一次跳的时候就有两种不同的选择:
- 一是第一次只跳1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1);
- 另外一种选择是跳一次跳2级,此时跳法数目等于后面剩下的n-2级台阶的跳法数目,即为f(n-2)。
- 因此n级台阶的不同跳法的总数f(n)=f(n-1)+f(n-2)。分析到这里,我们不难看出这实际上就是斐波那契数列了。
- 牛逼的思路!
题5:变态跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
思路:
- 首先也是小样本测试例子,在上面基础上再补充就好:
- 1级台阶:1种跳法
- 2级台阶:2种跳法
- 3级台阶:3+1=4种跳法
- 4级台阶:5+3=8种跳法
- 5级台阶:8+8=16种跳法
- 咦,发现了规律是2的平方?为什么呢?先写代码!
# -*- coding:utf-8 -*-
class Solution:
def jumpFloorII(self, number):
# write code here
import math
# 注意边界条件
if number <= 0:
return 0
return math.pow(2,number-1)
至于为什么,直接数据归纳法?牛逼。。。
题6:矩形覆盖问题
我们可以用2×1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2×1的小矩形无重叠地覆盖一个2×n的大矩形,总共有多少种方法?
- 本质还是斐波那契数列
- 小样本测试来看。
- n=1,1竖 = 1
- n=2,2竖 + 2横 = 2
- n = 3,3竖 + 2横1竖 + 1竖2横 = 3
- n = 4,4竖 + 2横2竖 + 2竖2横 + 1竖2横1竖 + 4横 = 5
- 符合斐波那契!
# -*- coding:utf-8 -*-
class Solution:
def jumpFloor(self, number):
# write code here
# 注意边界条件
if number <= 0:
return 0
alist = [1,2]
if number == 1:
return 1
elif number == 2:
return 2
else:
for i in range(2, number):
alist.append(alist[i-1] + alist[i-2])
return alist[number-1]