蓝桥杯python笔记(未完待续)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


(一)解题惯用:

0、库函数

   import math
   import datatime
   import calendar
   import decimal
   import itertools

1、读入:

①连续读入多个整数中间用空格隔开,存储在列表里:
l=list(map(int,input().split()))#注意input和split后面都是有括号的
②一行打不下,反斜杠“\”换行
③题目中文字描述的限制条件建议加进去,以防万一,(数据规模可以忽略
④如果需要直接存取的特性可以考虑用二维数组记录一种二维关系,注意创建二维数组时避免触发引用机制。
这种方式也可以很好的表现链式关系

2、输出:

①进制转换:
输出为十进制:a=int(s,number)#将number进制的字符串形式转换为十进制

>>> int('101',2)   5
输出为二、八、十六进制的字符串:函数:bin()/oct()/hex();参数:0b/0o/0x
>>> oct(0x9)   '0o11'

②格式化输出:
print(‘{}’.format())#注意大括号是在引号里面的,大括号内的五个顺序是:
: 号+填充的字符,只能是一个字符,不指定则默认是用空格填充。
^, <, > 分别是居中、左对齐、右对齐,后面+宽度(整数,
b、d、o、x 分别是二进制、十进制、八进制、十六进制。
③print()函数:
print(),没有参数时,就可以换行;print(‘\n’)内部换行,会换两行
print(a,b)时,a与b之间默认有一个空格,可以用sep=‘\n’或sep=’‘来更改
print()函数的末位默认是换行,end=’ ‘或end=’'来更改
④注意题目的通用描述,输入输出的要求,有没有类似“出现返回位置、不出现返回-1”的描述

3、列表:

①列表推导式创建一维列表:l=[0 for x in range(n)];二维列表:l=[[0]*n for x in range n]
PS.不要用【一维列表】*n去生成二维列表,因为会牵连改变
②for x in range(0):#x没有值,不进入循环
③对比list(列表)和dict(字典)的操作:
索引:自然数i/不可变类型key
添加:l.append()后面、l.extend()扩展、l.insert(i,v)中间插入/d[k]=v
删除:l.pop()、del l[i]/pop
注:pop()函数用于删除某个值并返回,它在列表中默认返回最后一个值,也可以指定index,
在集合中随机返回一个值,在字典中返回指定key的value
更新:l[index]=v/d[key]=v
正查:l[i]、l[i:j]/d[key]
反查:l.index(v)、l.count(v)/字典不能反查!可能有不同key相同value的情况出现
其它:l.reverse()时间复杂度O(n)、l.sort(reverse=True)时间复杂度O(nlog n)都是在原列表上改动
④列表中移除某元素用:list.remove()移去他的第一个匹配项,del list[index]可以删掉下标为index的元素

4、字符串:

①字符串大写:s.upper();字符串小写:s.lower();字符串首字母大写:s.title()
②字符串逆序的方法是:s[::-1],回文是指字符串逆序之后与原先相同

5、字典:

①空字典花括号{},空集合用set()
②d.keys()和d.values()返回键或值的列表

6、数学函数

①求x的次方:x**y、math.pow()[效率更高]
②abs():内置绝对值函数,无需引用math库
③整形的阶乘函数:math.factorial(int)
③求对数:math.log10(x):以十为底x的对数 math.log2(x):以2为底x的对数
math.log(x):以e为底x的对数 math.log(m,n):以n为底m的对数
十进制正整数n的位数为int(log10(n))+1

7、常识类

①闰年:年份(能被四整除 and 不能被100整除)or 能被400整除,润年366天,平年365天
if中的复杂条件可以用()来表示优先级,实际上优先级 not > and > or
②杨辉三角:所有行数字左对齐,第n行有n个数,第一列数字都是1,其余每个数是其左上和正上的数字和

(二)类型题

一、模拟:

用变量描述一件事的初始状态,再用数据模拟它发生的过程,得到最终的结果。其重点在于如何把一些过程 or 条件转变为可以机器实现的代码。这种题可能会有简便的做法,但可能性微乎其微。
流程:读入数据 -> 设置模拟过程所需变量(字符、数字、布尔值……)-> 输出(注意格式)
1、思路
①要学会阶段性地模拟事情发生的经过,巧妙地设置变量,让每个事情的发生作为影响变量的结果被记录下来
②一定要注意题目中文字描述给的数据类型,不要仅靠例子来判断(整数是int,浮点数是float)
③对于数字很多的题,写循环时要学会找某一轮代入计算,注意首轮和末轮,
如果可以的话要学会设置print()进行调试,往往会比自己凭空想象效率要高
④一堆数字找规律的话可以对齐看(左对齐 or 右对齐)
2、知识点
①矩阵对角线下标的特征:上对角线下标和相等,下对角线下标差相等
②矩形的表示法:一个矩形可以用对顶点坐标唯一确定,即(左下x,左下y,右上x,右上y)
③环形队列:只需要(下标+1)%n,就可以从n-1变到0了,即尾到首
④eval()执行一个字符串表达式,他把输入的字符串当做代码,返回其结果。适用于直接用字符构造表达式。

>>> eval("2+2")  4   >>> eval("abs(-2)")  2

⑤在某件事情结果的可能性比较少的时候,即使用字典枚举也很快。
3、例题
①感冒蚂蚁问题:感冒的蚂蚁左边向右走和右边向左走的蚂蚁都会被感染,因为蚂蚁掉头无需考虑,碰头的蚂蚁就像相互接替了对方的路线

②最大子列和问题:用dp[i]表示以第i个数结尾的最大子列和,则dp[i+1]=max(dp[i]+num[i],num[i])

二、高精度

主要包括三个方面:
1、整数任意长度的加法、乘法、阶乘(可以直接计算):python的int有无限精度;
2、浮点数精度计算(需要decimal库):

①decimal.getcontext().prec=10000 #指定精度(包括小数点前的)
②decimal.Decimal(input().strip()) #读入小数

3、方程求解(暴破):

a,b,c,d=map(float,input().split()) #浮点数
x=-100
count=0
while(x<100):
  if(abs(a*x**3+b*x**2+c*x+d)<0.0001): #精度绝对值!!!
    print("{:.2f}".format(x),end=' ')
    x+=1
    count+=1
  else: #要么加1要么加0.01
    x+=0.01   
  if(count==3):
    break

三、排序

四、递归和递推

五、贪心

六、二分

七、搜索

八、树

九、数学

(三)数据结构和算法

一、Python数据结构:

1、栈

数据的增和删只能发生在栈顶,存取特性为翻转次序,后进先出。pop:l.pop()/push:l.append()
①括号匹配:
遇到左括号进一个栈,遇到右括号出一个栈,然后检测出栈的左括号是否匹配。最后字符扫描完栈需要为空
注:在判断括号匹配时,由于不知道某括号的类型(大、中、小),因此可以用两个列表反查的方法:
opens=[‘(’,‘[’,‘{’],closes=[‘)’,‘]’,‘}’],判断opens.index©是否等于closes.index©
②进制转换:
算法:求余数入栈(%)、整除得到新数(//)、新数不为零继续循环,最后for循环将栈pop()出就可以反向。
应用:时分秒就是六十进制转化
③表达式转换:
中缀–>后缀:按运算顺序给表达式加上括号,左括号删掉,每个操作符移到相应的右括号处
中缀–>前缀:按运算顺序给表达式加上括号,右括号删掉,每个操作符移到相应的左括号处
中->后算法:一个空栈存操作符,一个空表存输出结果,split()函数将表达式形成列表,
扫描此列表,遇到一个操作数将其放入输出列表,遇到一个左括号就入栈,
遇到一个操作符就判断其和栈顶操作符的优先级然后入栈,(栈中必须为高优先级的在上面低优先级的在下面,可以记忆做:上面的先出栈,需要先做,所以一定是优先级较高的运算符)
遇到右括号就将其对应左括号之前的所有符号出栈,最后扫描完毕将所有符号出栈。
可用字典记录运算符优先级:d={‘*’:3,‘/’:3,‘+’:2,‘-’:2,‘(’:1,‘)’:1}
④后缀表达式求值:
一个空栈存操作数,从左到右扫描单词列表,扫到操作数就进栈,扫到操作符就弹出两个操作数计算,
然后把结果入栈,直至扫描完,栈顶的值就是结果

2、队列

数据项的添加和移除发生在序列两端,存取特性为先进先出。入:l.insert(0,x),出:l.pop()
①热土豆问题(击鼓传花):一个人出队再入队就像一次传递。
②回文词判定:双端队列是两边都可以插入 or 删除的一种队列,但不能从中间插入或删除。
从双端队列两端同时移除字符并判断是否相同,直至其中只剩下一个字符。

3、树

主要考察二叉树,即每个节点最多有两个子节点。
列表实现二叉树:用递归嵌套实现 [root,left,right] #根、左子树、右子树

def binaraytree(r):#建树
  return [r,[],[]] #只有根结点,没有左右子树

def insertLeft(root,newBranch):#插入左孩子
  t=root.pop(root[1])
  if(len(t)!=0):
    root.insert(1,[newBreanch,t,[]]) #原先的左子树还放在左子树
  else:
    root.insert(1,[newBranch,[],[]]) #没有左子树
return root

def insertRight(root,newBranch):#插入右孩子
  t=root.pop(2)
  root.append([newBranch,[],t])

需要注意的是列表属于可变类型,因此可以通过修改任何一个子树的引用改变二叉树的值

4、图

一般考察的是有向图,有向图的实现有邻接矩阵和邻接表,邻接矩阵较为简单,但可能存在稀疏矩阵导致空间浪费的情况,邻接表可以快速找到一个点的出边,但是如果要找某一个点的入边需要遍历整个表,优点是存储更高效。
由图引出的两个算法是深度优先遍历(DFS)和广度优先遍历(BFS),如果把图的结点看做树的节点,从某个起始位置进行搜索,此位置作为树的根结点,距离起始位置边数为1的点在第一层,距离起始位置边数为2的点在第二层……那么广度优先搜索就是逐层建立搜索树,而深度优先搜索是沿着树的单支尽量深入向下搜索,若无法继续,则回溯返回。
从更抽象的意义上来讲,如果把搜索的起始位置看做一种初始状态,将边数看做状态改变因素,将遍历到叶节点看做目标状态,则dfs搜索算法是一种类似暴破但效率更高的解题方法。

二、Python算法:

1、排序:

①冒泡排序:
每轮找最小的放在最前面,第n次保证前n个最小的在上面(前n个是有序的),共需要n次排序,
第i次排序需要(i-1)次交换。

'''
冒泡排序,两个for循环,O(n^2)
第一个是轮数,第二个是指针
'''
#i代表排队的轮数,j代表每轮的指针,指向对比的两个元素中的第一个(下标
for i in range(len(l)-1):#因为要前一个和后一个对比,所以减掉最后一个对比的步骤
    temp=0#记录本轮是否发生交换,若没有,说明已经有序,直接退出
    for j in range(len(l)-i-1):#第i=1(二)轮减去第一轮已经排好的最后一个,已经拍好的
        if(l[j]>l[j+1]):
            l[j],l[j+1]=l[j+1],l[j]
            temp=1
    if(temp==0):break

②选择排序

'''
选择排序,两个for循环,O(n^2)
第一个是选择出来放最大值的下标,第二个是遍历求最大值
'''
for i in range(len(l)-1):#最后一个自然有序
    temp=0
    for j in range(len(l)-i):#除了最后已经排好的
        if(l[j]>l[temp]):#记录最大的元素的下标
            temp=j
    l[temp],l[len(l)-1-i]=l[len(l)-1-i],l[temp]#最大的元素和最后一个元素交换

③插入排序

'''
插入排序,两个for循环,O(n^2)
第一个指向当前需要向前插入的元素,第二个遍历前面的有序序列
'''
for i in range(1,len(l)):#指针,指向当前需要向前插入的元素
    if(l[i]<l[0]):
        l.insert(0,l.pop(i))#如果比有序序列的第一个还小,直接插入第一个
    else:
        for j in range(i):#需要遍历的有序序列
            if(l[j]<l[i] and l[j+1]>l[i]):#寻找有序序列中合适的位置
                l.insert(j+1,l.pop(i))

2、一个单词中,对出现的字母进行计数:

①设一个l=[0]*26的列表记录,对应a~z出现的次数:

for i in s:
    temp=ord(i)-ord('a')
    l[temp]+=1

②ord(‘a’)是97,chr(97)是 ‘a’

3、递归

def digui(层数,参数):
    if(基本结束条件):
        终止操作
        return
    处理当前参数
    digui(层数+1,新参数)#减少问题规模+调用自身
    清理当前层数据

注:递归三定律:基本结束条件、减少问题规模、调用自身

4、dfs深搜:

def dfs(状态改变因素):
  设置当前状态(假设,利用状态改变因素得到一个新的状态)
  if(当前状态是目标状态):
    do something
  else:
    for 每一个直接可达状态:
      if 新状态合法:
        dfs(新状态)
        (回溯?????
dfs(初始状态)#调用函数

5、快速幂算法:

##整数快速幂算法(递归法
'''
首先,幂数会被表示为二进制系数,
其位数即为结果的项的个数,最后某项是否被乘进去需要看此项的系数是否为1,若为0则
'''
x=int(input())
n=int(input())
def quick_power(x, n):
        # 特殊情况
        if n == 0:
            return 1

        # 递归过程的最后一层
        elif n == 1:
            return x

        # 如果幂的值为偶数, 则 不 进行记录,传给下一层
        else:
            y=quick_power(x,n//2)#递下去
            print(y)
            if(n&1):#n的末位是不是1
                return (y**2)*x
            return(y**2)
print(quick_power(x, n))

##矩阵快速幂算法(递归法
def matrix_mul(A, B):
#矩阵乘法函数,返回两个矩阵相乘的值,建议背诵
    return [[sum(a * b % 99999999 for a, b in zip(col, row)) % 99999999 for col in zip(*B)] for row in A]

def matrix_pow(A, n):
    size_ = len(A)
    if n == 0:#返回单位矩阵
        res = [[0 for _ in range(size_)] for _ in range(size_)]
        for i in range(size_):
            res[i][i] = 1
        return res
    elif n == 1:#返回自己
        return A
    else:
        y = matrix_pow(A, n // 2)
        if n & 1:#要乘
            return matrix_mul(matrix_mul(y, y), A)
        return matrix_mul(y, y)#不乘

6、埃氏筛法:

要得到自然数n以内的全部素数,只需要把不大于根号n的所有素数的倍数都剔除。具体的做法是建立一个长度为n的列表,列表值0或1是此数是否为素数的flag,然后对0~根号n的数进行按次序遍历,对于每个flag为1的数,把他的倍数都变为0(while 循环)。最后flag为1的数即为素数。

'''
要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。
'''

import math #引用math库

n=int(input()) #读入n
is_prim=[True] * (n+1) #为每一个数建立一个标志位,初始全为True

for i in range(2,int(math.sqrt(n))+1): #对于根号n以下的数
    if(is_prim[i]==True): #找到一个素数
        r=i*2
        while(r<=n):#把他的倍数都设为Flase
            is_prim[r]=False
            r+=i 

for i in range(2,n+1):
    if(is_prim[i]==True): #将标志位仍为True的数读出
        print(i)
        

7、动态规划:

①背包问题

#宝物的重量和价值
x=[0,[2,3],[3,4],[4,8],[5,8],[9,10]]
W=20

l=[[0]*21]*6

for i in range(1,6):
    for w in range(1,21):
        if(x[i][0]>w):
            l[i][w]=l[i-1][w]
        else:
            l[i][w]=max(l[i-1][w-x[i][0]]+x[i][1],l[i-1][w])
        if(l[i][w]==40):
            print(i,w)
        


②找零问题

def dpMakeChange(coinValueList,change,minCoins):#传入各个币值的列表、需要找零的数目、对应每个找零数目的最小硬币个数
    for x in range(0,change+1):#range()函数左闭右开,从小到大算0~目标值的最小硬币数
        temp=x #初始化一个最大值用于比较,暂存
        for j in [c for c in coinValueList if c<=x]: #每个找零值求硬币数的方法是,对于每个比他小的币值,优解
            if(minCoins[x-j]+1<temp):#减去该币值并引用之前的最优解,将银币数目加一,与现有作比较,若比现有小,
                    temp=minCoins[x-j]+1 #将暂存值改为更小的
        minCoins[x]=temp #暂存值填入列表供后面计算使用
    return minCoins[change]#循环结束返回最终结果

print(dpMakeChange([1,5,10,21,25],63,[0]*64)) #找零63做实验

(四)常用标准库

1、标准库calendar的使用

import calendar #输出日历

print(calendar.isleap(2007))
#①判断指定是否是闰年.闰年为True,平年为False.此处2018年是平年,返回false

print(calendar.leapdays(2008,2011))
#②返回两年份之间的闰年数量。包括起始年,不包括结束年。此处仅08年是闰年,故返回1

print(calendar.weekday(2010,9,1))
#③返回获取指定日期为星期几,注意返回值代表的是下标,0是星期一,…,6为星期日

calendar.setfirstweekday(firstweekday=6)
#④指定一周的第一天,0是星期一,…,6为星期日,故此处将周日设为一周的第一天

'''
⑤
month(theyear, themonth, w=0, l=0)返回一个月的日历的多行文本字符串。
theyear指定年份,themonth指定月份,
w每个单元格宽度,默认0,最小宽度为2,
l每列换l行,默认为0,至少换行1行
e.g.输出2010年九月的日历(split()按换行符分割)
'''

l=calendar.month(2010,9,2).split('\n')
for i in range(2,len(l)):
    print(' ',l[i],sep='')

2、标准库itertools的使用

#import itertools
#print(list(itertools.permutations([1,2,3],3)))


'''
全排列函数
递归法
注:递归函数如果需要计数那么需要设置全局变量(global
'''

def qpl(n,begin):#n是需要排序的列表,begin是本次需要排列的头指针(下标),也可以看作是前面已固定的元素个数
    end=len(n)#记录元素个数
    if begin==end: #递归的结束条件,全部都已固定,可以输出
        print(n)
    else:
        i=begin #指向本次需要排列的第一个位置(本轮需要固定的位置
    for num in range(begin,end):#num遍历本次需要排列的序列中的每一个数,
        n[num],n[i]=n[i],n[num]#依次把这些数放在固定的位置上,方法是交换
        qpl(n,begin+1) #不看那个已经固定的数
        n[num],n[i]=n[i],n[num] #回溯,回到上一步,再进行下一次for循环

n=[1,2,3]
qpl(n,0)

3、标准库decimal的使用

#高精度加法库 decimal
from decimal import *
#有界精度:用于存储数字的位数是固定的,默认28,此处需要扩大,最大10000位
#可以通过decimal.getcontext().prec=x 来设定,不同的数字可以有不同的精度
getcontext().prec = 10000
m=Decimal(input().strip())
n=Decimal(input().strip())

print(m+n)

4、标准库datatime的使用

import time
import datetime

timestamp = 46800999

#PYTHON中tmie.gmtime()获取的时间为UTC时区(0时区)的struct_time,
#但是我们计算机显示的是东八区时间(+8),所以将得到的struct_time-8才为现在计算机显示的时间(按照所处不同时区计算)。

#转换成localtime
time_local = time.localtime(timestamp/1000)
print(time_local)

#转换成新的时间格式(精确到秒)
#dt = time.strftime("%Y-%m-%d %H:%M:%S", time_local)
#应该是13,输出是21,输出时应该减去8

a = time.strftime("%H:%M:%S", time_local)
l=a.split(':')
l[0]=str((int(l[0])-8)%24)
s=':'.join(l)
print(s) 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值