二叉树简介
用数组表示一棵树,第一个元素是根节点,某一节点位置为i,其左子节点为2i+1,右子节点2i+2,父节点为(i-1)//2
树的遍历顺序:前序遍历,中序遍历,后序遍历(前中后对应的根的位置,前序遍历为根左右,中序遍历为左根右,后序遍历为左右根)
#树的三种遍历顺序
def preorder(alist,i):
if i>len(alist)-1:
return
if i<=len(alist)-1:
print(alist[i]) #根
preorder(alist,2*i+1) #左
preorder(alist,2*i+2) #右
def inorder(alist,i):
if i>len(alist)-1:
return
if i<=len(alist)-1:
preorder(alist,2*i+1)
print(alist[i])
preorder(alist,2*i+2)
def postorder(alist,i):
if i>len(alist)-1:
return
if i<=len(alist)-1:
preorder(alist,2*i+1)
preorder(alist,2*i+2)
print(alist[i])
textlist=[1,2,3,4,5,6,7]
堆排序
大顶堆:
对应到数组中:
思路:
将待排序序列构造成一个小顶堆,此时,整个序列的最小值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最小值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
#小顶堆,最后利用堆排序是倒序数组
def makeminheap(alist):
for index in range(len(alist)//2-1,-1,-1):
heapadjust(alist,index,len(alist)-1)
def heapadjust(alist,index,n):
#找到左右子树
left=2*index+1
right=2*index+2
#左子树已经越界,index对应的是叶子节点
if left>n:
return
min=left
if right>n:
min=left
else:
if alist[right]<alist[left]:
min=right
#min指向了左右子树中较小的那个
#如果A【i】比两个子树都要小,不用调整
if alist[index]<=alist[min]:
return
#否则,找到两个子树中较小,进行交换
else:
alist[index],alist[min]=alist[min],alist[index]
#较小子树位置对应的值发生了变化,index变更到那个位置,递归调整
heapadjust(alist,min,n)
def heapsort(alist):
makeminheap(alist)
for i in range(len(alist)-1,0,-1):
alist[0],alist[i]=alist[i],alist[0]
heapadjust(alist,0,i-1)
计数排序
牺牲空间换时间
思路:找出原数组中元素值最大的,创建一个新全零数组,其长度是最大值加1,
遍历原数组中的元素,以原数组中的元素作为新全零数组的索引,以原数组中的元素出现次数作为新数组的对应索引的元素值。
遍历处理完的新t数组,找出其中元素值大于0的元素,将其对应的索引作为元素值填到原数组中去,每处理一次,count中的该元素值减1,直到该元素值不大于0,依次处理count中剩下的元素,返回原数组
textlist=[3,1,10,29,13,10]
maxnum=max(textlist)
helper=[0]*(maxnum+1)
for i in textlist:
helper[i]+=1
n=0
while n<=len(textlist)-1:
for i in range(len(helper)):
while helper[i]>0:
helper[i]-=1
textlist[n]=i
n+=1
print(textlist)
练习题:
例题1 排序数组找和的因子
如果只是简单想将所有情况组合看和的结果,那么复杂度为n!没有利用到排序数组这一条件
思路:(双指针)
确定两个指针指向数组两端,左指针向右移动,右指针向左移动,因为是排好顺序的,那么左右指针对应值相加。如果大于目标值,说明应该减小,那么,右指针左移;如果小于目标值,说明应该增大,那么,左指针右移;等于目标值则返回。
def solution(alist, target):
left = 0
right = len(alist) - 1
res=[]
while left < right:
if alist[left] + alist[right] < target: #如果小于目标值,左指针右移
left += 1
elif alist[left] + alist[right] > target: #如果大于目标值,右指针左移
right -= 1
else:
res.append(alist[left])
res.append(alist[right])
left+=1
return res
textlist = [-8,-4,-3,0,2,4,5,8,9,10]
target = 10
print(solution(textlist, target))
例题2 需要排序数组的长度
思路:(双指针)
从左向右遍历,遍历的过程记录左侧出现过的数的最大值。记为maxnum。假设当前数为alist[i],如果alist[i]<maxnum,说明不是持续上升,开始下降,需要排序,maxnum的值需要移到alist[i]的右边。用变量end记录需要调整数组的右边界。
从右向左遍历,遍历的过程记录右侧出现过的数的最小值,记为minnum。假设当前数为alist[i],如果alsit[i]>minnum,minnum值需要排序,需要移到alisti]的左边。用变量start记录需要调整数组的左边界。
如果遍历完成后,end值依然为len(alist)-1,start的值依然为-1,说明从右向左始终不升序,原数组本来就有序,直接返回0,即完全不需要排序。
遍历完后,alist[start…end]是真正需要排序的部分。返回它的长度即可。
def findsegement1(alist,n):
start=n-1
end=0
maxnum=alist[0]
minnum=alist[-1]
for index in range(n): #从左向右遍历
if alist[index]>=maxnum: #更新最大值
maxnum=alist[index]
if alist[index]<maxnum: #alist[i]<maxnum,
#maxnum的值需要移到alist[i]的右边
end=index #用变量end记录需要调整数组的右边界
for index2 in range(n-1,-1,-1): #从右向左遍历
if alist[index2]<=minnum: #更新最小值
minnum=alist[index2]
if alist[index2]>minnum: #alist[i]>minnum
#minnum的值需要移到alist[i]的左边
start=index2 # 用变量start记录需要调整数组的左边界
if start==n-1 and end==0: #原数组本来就有序,返回0
return 0
else:
return end-start+1
题目没说排序最后排成什么顺序,也许排从小到大困难,但是排成从大到小简单
因此需要比较这两种排序哪种更短
def findsegement2(alist,n):
start=n-1
end=0
minnum=alist[0]
maxnum=alist[-1]
for index in range(n):
if alist[index]<=minnum:
minnum=alist[index]
if alist[index]>minnum:
end=index
for index2 in range(n-1,-1,-1):
if alist[index2]>=maxnum:
maxnum=alist[index2]
if alist[index2]<maxnum:
start=index2
if start==n-1 and end==0:
return 0
else:
return end-start+1
比较两种排序,返回其中较小值
例题3 topK问题
思路:海量数据无法直接储存,那就只储存k个数,这k个数按堆排列(大顶堆),当输入新数据,和数组第一个元素(根节点)比较,他是数组中最大的元素,如果比他小,将新加入的数据设为根节点值,在向下调整;如果比他大,则说明他无需加入。
k=int(input()) #正序排序后前k个数
numlist=[]
num=int(input())
while num!=-1: #输入为-1时停止
if len(numlist)<k: #数组长度小于k
numlist.append(num) #继续添加数字
makemaxheap(numlist) #进行堆调整 (大顶堆)
elif len(numlist)==k: #数字长度等于k
if num<numlist[0]: #如果堆顶数字(堆顶数字代表的是最小的数字)小于待加入数字
numlist[0]=num #更改堆顶数字
makemaxheap(numlist) #进行堆调整
num=int(input())
print(numlist)
例题4.员工年龄排序问题
思路:桶排序
所有员工的年龄都在一个范围内,例如0到99,初始化一个大小为100的数组alist(数组中所有元素初始为0),遍历所有员工年龄,将员工年龄的人数放到数组的对应位置上alist[0],将员工年龄为1的人数放到数组的第1个位置alist[1]…将员工年龄为99的人数放到数组的第99个位置alsit[99],遍历这个数组alist,将员工年龄(数组alist下标)重新编写到年龄数组中。代码参考桶排序
例题5.数组能排成的最小数
题解参考leetcode题解
排序判断规则: 设 nums 任意两数字的字符串格式 x和 y ,则
若拼接字符串 x + y > y + x,x+y>y+x ,则 m > n,m>n ;
反之,若 x + y < y + x,x+y<y+x ,则 n < m,n<m ;
根据以上规则,套用任何排序方法对 nums 执行排序即可
算法流程:
初始化: 字符串列表 strsstrs ,保存各数字的字符串格式;
列表排序: 应用以上 “排序判断规则” ,对 strs 执行排序;
返回值: 拼接 strs中的所有字符串,并返回。
此题求拼接起来的 “最小数字” ,本质上是一个排序问题。
为什么要按上述排序?
以下是证明:
根据算法,如果a < b,那么a排在b前面,否则b排在a前面。可利用反证法,假设排成的最小数字为xxxxxx,并且至少存在一对字符串满足这个关系:a > b,但是在组成的数字中a排在b前面。根据a和b出现的位置,分三种情况考虑:
(1)xxxxab,用ba代替ab可以得到xxxxba,这个数字是小于xxxxab,与假设矛盾。因此排成的最小数字中,不存在上述假设的关系。
(2)abxxxx,用ba代替ab可以得到baxxxx,这个数字是小于abxxxx,与假设矛盾。因此排成的最小数字中,不存在上述假设的关系。
(3)axxxxb,这一步证明麻烦了一点。可以将中间部分看成一个整体ayb,则有ay < ya,yb < by成立。将ay和by表示成10进制数字形式,则有下述关系式,这里a,y,b的位数分别为n,m,k。
关系1: ay < ya => a * 10^m + y < y * 10^n + a => a * 10^m - a < y * 10^n - y => a( 10^m - 1)/( 10^n - 1) < y
关系2: yb < by => y * 10^k + b < b * 10^m + y => y * 10^k - y < b * 10^m - b => y < b( 10^m -1)/( 10^k -1)
关系3: a( 10^m - 1)/( 10^n - 1) < y < b( 10^m -1)/( 10^k -1) => a/( 10^n - 1)< b/( 10^k -1) => a*10^k - a < b * 10^n - b =>a*10^k + b < b * 10^n + a => a < b
这与假设a > b矛盾。因此排成的最小数字中,不存在上述假设的关系。
综上所述,得出假设不成立,从而得出结论:对于排成的最小数字,不存在满足下述关系的一对字符串:a > b,但是在组成的数字a出现在b的前面。从而得出算法是正确的
此题求拼接起来的 “最小数字” ,本质上是一个排序问题。
排序判断规则: 设 numsnums 任意两数字的字符串格式 xx 和 yy ,则
若拼接字符串 x + y > y + x,x+y>y+x ,则 m > n,m>n ;
反之,若 x + y < y + x,x+y<y+x ,则 n < m,n<m ;
根据以上规则,套用任何排序方法对 numsnums 执行排序即可
def minNumber(self, nums: List[int]) -> str:
def fast_sort(l , r):
if l >= r:
return
i, j = l, r
while i < j:
while strs[j] + strs[l] >= strs[l] + strs[j] and i < j:
j -= 1
while strs[i] + strs[l] <= strs[l] + strs[i] and i < j:
i += 1
strs[i], strs[j] = strs[j], strs[i]
strs[i], strs[l] = strs[l], strs[i]
fast_sort(l, i - 1)
fast_sort(i + 1, r)
strs = [str(num) for num in nums]
fast_sort(0, len(strs) - 1)
return ''.join(strs)
作者:jyd
链接:https://leetcode-cn.com/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof/solution/mian-shi-ti-45-ba-shu-zu-pai-cheng-zui-xiao-de-s-4/
来源:力扣(LeetCode)