一、上三角
1、方法一:基本方法,前面空格、后面数字,定好 n 后,每行宽度即定,再依据 j 自身宽度控制空格
#弊端:虽然能打印整齐,但每次都要根据j的位数计算一次空格的个数,即' '*len(str(j))
def triangle(n):
for i in range(1,n+1):
for j in range(n,0,-1):
if j>i:
print(' '*len(str(j)),end=' ')
else:
print(j,end=' ')
print()
triangle(12)
2、方法二:对齐方式;右对齐,最大宽度以最后一行为准
#两层循环,tail为最后一行的字符串
def triangle(n):
tail=' '.join(str(i) for i in range(n,0,-1))
length=len(tail)
for i in range(1,n):
print('{:>{}}'.format(' '.join(str(j) for j in range(i,0,-1)),length))
print(tail)
triangle(12)
3、方法三:利用方法二的 tail 字符串结果切片打印,切片的起始端开始是 -1,每逢10的整数次幂、起始端左移的长度加1
def triangle(n):
tail=' '.join(str(i) for i in range(n,0,-1))
length=len(tail)
s={10**i for i in range(1,length)}
start=1
step=2
for i in range(1,n):
start-=step
print('{:>{}}'.format(tail[start:],length))
if i+1 in s:
step+=1
print(tail)
triangle(12)
4、方法四:对方法二的改进,将字符串换成列表,打印时用一个 for 循环,辅以列表切片
def triangle(n):
tail=[str(i) for i in range(n,0,-1)]
length=len(' '.join(tail))
for i in range(1,n+1):
print('{:>{}}'.format(' '.join(tail[n-i:]),length))
triangle(12)
5、方法五:对 tail 字符串切片打印,转折点为索引处出现空格,format 右对齐
def triangle(n):
tail=' '.join(str(i) for i in range(n,0,-1))
length=len(tail)
for i in range(length):
if tail[-i] == ' ':
print('{:>{}}'.format(tail[-i+1:],length))
print(tail)
triangle(12)
二、下三角
1、方法一:对 tail 字符串切片打印,转折点为索引处出现空格,打印空格以对齐
def triangle2(n):
tail=' '.join(str(i) for i in range(n,0,-1))
print(tail)
for i in range(len(tail)):
if tail[i] == ' ':
print(' '*i,tail[i+1:])
triangle2(12)
总结:
1、计算好最长的一行,其它行均利用该结果进行切片操作,最省空间,时间上只用一层循环,且每次循环用索引找值,减少计算;
2、相比于打印空格使格式整齐,提前算好最大宽度再用 format 函数右对齐更便利
三、冒泡排序、选择排序、插入排序的汇总
1、冒泡排序
import random
l=[random.randint(1,20) for _ in range(10)]
print(l)
for i in range(len(l)-1):
swap_count=0
for j in range(len(l)-1-i):
if l[j]>l[j+1]:
l[j],l[j+1]=l[j+1],l[j]
swap_count+=1
if swap_count==0:
break
print(l)
2、选择排序
import random
l=[random.randint(1,20) for _ in range(10)]
print(l)
for i in range(len(l)-1):
small=i
for j in range(i+1,len(l)):
if l[small]>l[j]:
small=j
l[small],l[i]=l[i],l[small]
print(l)
3、插入排序
import random
l=[random.randint(1,20) for _ in range(10)]
print(l)
l=[0]+l
for i in range(2,len(l)):
l[0]=l[i]
while l[0]<l[i-1]:
l[i-1],l[i]=l[i],l[i-1]
i-=1
l[i]=l[0]
print(l[1:])
四、递归
1、斐波那契数列
#原始版本,每一条分支都没有利用到之前的计算结果
def fib(n):
if n<3:
return 1
else:
return fib(n-1)+fib(n-2)
#优化:利用到上次的计算结果
def fib(n,pre=0,cur=1):
pre,cur = cur,pre+cur
if n==1:
return pre
else:
return fib(n-1,pre,cur)
print(fib(5))
#参数可直接提到形参中
def fib(n,pre=0,cur=1):
if n==1:
return cur
else:
return fib(n-1,cur,pre+cur)
print(fib(5))
# 面向对象方法,利用上次缓存结果
class Fib:
def __init__(self):
# 使用缓存,减少计算
self.items=[0,1,1]
def __call__(self,index):
if index>=len(self.items):
for i in range(len(self)+1,index+1):
self.items.append(self.items[i-1]+self.items[i-2])
return self.items[index]
def __getitem__(self,index):
return self(index)
# 获取长度
def __len__(self):
return len(self.items)-1
# 解决迭代问题,把fib对象当可迭代对象
def __iter__(self):
return iter(self.items)
fib=Fib()
# 虽然内部都是用call方法实现,但调用的意义完全不同
print(fib(5)) # 把实例当可调用实例来看
print(fib[5]) # 把实例当可索引的list或dict来用
for x in fib:
print(x)
2、求阶乘
#基本形式
def fac(n):
if n==1:
return 1
else:
return n*fac(n-1)
#传参形式
def fac(n,f=1):
if n==1:
return f
else:
return fac(n-1,f*n)
3、猴子吃桃
def peach(d=10,s=1):
if d==1:
return s
else:
return peach(d-1,2*(s+1))
print(peach())
4、将一个数逆序放到列表中,1234 -> [ 4,3,2,1]
#递归切片,方法一
def unlist(n,l=[]):
l.append(n[-1])
if len(n)==1:
return l
else:
return unlist(n[:-1],l)
print(unlist('1234'))
#递归切片,方法二
def unlist(n,l=[]):
if n:
l.append(n[-1])
return unlist(n[:-1])
else:
return l
print(unlist('1234'))
#递归切片,方法三,在循环中反复递归调用,循环结束、临界条件一个return,然后从内往外每一个函数调用都结束并return l,直至最外层,而l都是相同的
def unlist(n,l=[]):
if n:
l.append(n[-1])
unlist(n[:-1])
return l
print(unlist('1234'))
#数字整除方法
def unlist(n,l=[]):
n,s=divmod(n,10)
l.append(s)
if n==0:
return l
else:
return unlist(n,l)
print(unlist(1234))
5、字典扁平化
src:{‘a’:{‘b’:1,‘c’:2},‘d’:{‘e’:3,‘f’:{‘g’:4}}}
dst:{‘a.b’:1,‘a.c’:2,‘d.e’:3,‘d.f.g’:4}
这种字典一般深度也有限,故本题的考点为递归
正错代码示例:
x={'a':{'b':1,'c':2},'d':{'e':3,'f':{'g':4}}}
d1={}
#错误flatmap
def flatmap(src,newkey=''):
for k,v in src.items():
if isinstance(v,dict):
newkey=newkey+k+'.' #
flatmap(v,newkey)
else:
d1[newkey+k]=v
return d1
print(flatmap(x))
#修改后
d2={}
def flatmap2(dic, newkey=''):
for k, v in dic.items():
if isinstance(v,dict):
flatmap2(v,newkey+k +'.') #
else:
d2[newkey+k] = v
return d2
print(flatmap2(x))
#运行结果为
{'a.b': 1, 'a.c': 2, 'a.d.e': 3, 'a.d.f.g': 4}
{'a.b': 1, 'a.c': 2, 'd.e': 3, 'd.f.g': 4}
从内到外,对于引用类型,return的都是堆里的对象地址
也可对函数做一些调整
#把d={}放到形参里,而不是放在全局
x={'a':{'b':1,'c':2},'d':{'e':3,'f':{'g':4}}}
def flatmap(src, newkey='',d={}):
for k, v in src.items():
if isinstance(v,dict):
flatmap(v,newkey+k +'.')
else:
d[newkey+k] = v
return d
print(flatmap(x))
#改成嵌套函数,内层函数依然可以递归调用
x={'a':{'b':1,'c':2},'d':{'e':3,'f':{'g':4}}}
def flatmap(src):
d={}
def _flatmap(src, newkey=''):
for k, v in src.items():
if isinstance(v,dict):
_flatmap(v,newkey+k +'.')
else:
d[newkey+k] = v
_flatmap(src)
return d
print(flatmap(x))