【前言】
记录自己在刷蓝桥杯题目的一些做题思路,在构思的过程中,会参考一些大佬的代码( 用到了会提供相应的学习链接)。
内容有不恰当之处,请各位大佬们批评指正,我会第一时间进行更改。
语言:python
一、计算0到2020中2的个数
print("".join([str(i) for i in range(1, 2021)]).count("2"))
二、数列排序
import os
import sys
n = int(input())
m=input().split(' ')
lst=[]
for i in range(n):
lst.append(int(m[i]))
lst.sort()
for num in lst:
print(num,end=' ')
注:
①变量不能存在关键词list,str
②列表强行转换,不给过
例如:str[i] = int(str[i])
三、进制转换问题
#1、十进制->十六进制
print(hex(int(input(),10))[2:].upper())
#2、十六进制->十进制
n=0
for i in range(len(ans)):
n=n*8+ord(ans[i])-ord('0')
print(n)
#3、十六进制->八进制
m = input()
ans = oct(int(m,16))[2:]
t = int(input())
for i in range(t):
n = input()
ans = oct(int(n, 16))
print(ans[2:])
四、回文数
输入一个正整数n, 编程求所有这样的五位和六位十进制数,满足各位数字之和等于n 。
例如: 输入:52 输出: 899998 989989 998899
import os
import sys
n = int(input())
lst = []
sum = 0
for i in range(10000,1000000):
if str(i) == str(i)[::-1]:
lst.append(i)
k = lst[:]
/*注意:
1、列表复制分强复制和浅复制:
强复制: b=a[:], b=list(a), b=a*1, b=copy.copy(a)
浅复制:b=a,这样的话,会使b指向a列表的地址,a变b也变
*/
for i in range(len(lst)):
sum = 0
while k[i]!=0:
sum += k[i]%10
k[i] //= 10
if sum == n:
print(lst[i])
五、杨辉三角
输入:4
输出:
1
1 1
1 2 1
1 3 3 1
from sys import stdout
"""
第一种的思路
先填充一个n*n的矩阵列表
首尾加一
中间开始递加
输出
"""
n = int(input())
a = []
# 先填充
# [
# [0, 0, 0, 0],
# [0, 0, 0, 0],
# [0, 0, 0, 0],
# [0, 0, 0, 0]
# ]
for i in range(n):
a.append([])
for j in range(n):
a[i].append(0)
# 补填首尾两端的1
for i in range(n):
a[i][0] = 1
a[i][i] = 1
#开始相加
for i in range(2,n):
for j in range(1,i):
a[i][j] = a[i - 1][j-1] + a[i - 1][j]
# 输出
for i in range(n):
for j in range(i + 1):
print(str(a[i][j]),end=' ')
print()
第二种,利用zip函数取巧
zip函数学习链接
n = int(input())
m = 1
l1 = [1]
l2 = []
while m<=n:
l2.append(l1)
l1 = [sum(t) for t in zip([0]+l1,l1+[0])]
"""
zip()函数作用:假设L1为[1,1]
所以zip([0]+l1,l1+[0])]=zip([0,1,1],[1,1,0])
=[(0,1),(1,1),(1,0)]
通过sum()的作用,使得L1 = [1,2,1](这不就是第三层的列表值吗!!)
话说为什么会想到这个”[0]+l1,l1+[0]“?
1
1 1 0
1 2 1
1 3 3 1
其中121=[0+1,1+1,1+0],对应
0 1 1
1 1 0
"""
m += 1
#输出数值
for i in range(len(l2)):
for j in range(i+1):
print(l2[i][j],end=' ')
print()
六、 查找整数
def run():
n = int(input())
num_list = input().split()
search_num = input()
if search_num in num_list:
print(num_list.index(search_num) + 1)
else:
print(-1)
run()
第二种:
n = int(input())
lst = []
m = input().split()
for i in range(len(m)):
lst.append(int(m[i]))
k = int(input())#输入需要查找的值
for j in range(len(lst)):
if lst[j] == k:
print(j+1)
break
if j == len(lst)-1:
print(-1)
七、 字母图形
样例输入
5 7
样例输出
ABCDEFG
BABCDEF
CBABCDE
DCBABCD
EDCBABC
第一种(伪)
n, m = map(int, input().split())
letter = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
x = letter[:m]
for i in range(1, n + 1):
print(x)
x = letter[i] + x[0:-1]
#你在运行过程中,会发现输出26列时,会出现字符串溢出
第二种
n,m=map(int,input().split())
str1=[]
for i in range(m):
str1.append(chr(ord('A')+i))#这里的chr('a')就是把'a'转化为对应的整数;ord(97)就是把整数转化为对应的ASCII码值
for j in range(len(str1)):
print(str1[j],end='')
print()
for k in range(1,n):
str1.insert(0,chr(ord('A')+k))#首部插入新元素
str1.pop()#弹出末尾元素
for p in range(len(str1)):
print(str1[p],end='')#输出
print()#换行
八、01字串
for i in range(32):
print('{0:05b}'.format(i))
#输出五个数字,不足位数的用0补充
九、序列
Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1。
当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少。
第一种:80分,n过大时,内存超出
num = int(input())
fibs = [0,1]
for i in range(num-1):
fibs.append(fibs[-2]+fibs[-1]) #倒数第二个+倒数第一个数的结果,追加到列表
print(fibs[num]%10007)
第二种:100分
while True:#异常处理
try:
n=int(input())#键盘读入
F1,F2=1,1
for i in range(3,n+1):
F1,F2=F2%10007,(F1+F2)%10007#先取余再递推防止超时
#F1 = F2,F2 = F1+F2
print(F2)
except:
break
十、高精度加法
问题描述
输入两个整数a和b,输出这两个整数的和。a和b都不超过100位。
输入格式
输入包括两行,第一行为一个非负整数a,第二行为一个非负整数b。两个整数都不超过100位,两数的最高位都不是0。
输出格式
输出一行,表示a + b的值。
样例输入
20100122201001221234567890
2010012220100122
样例输出
20100122203011233454668012
a=input()
b=input()
B=list(b.zfill(max(len(a),len(b)))) #右对齐、前向补零使ab位数保持一致
A=list(a.zfill(max(len(a),len(b))))
n=len(A)
x,y=0,0
Sum=[0 for i in range(n+1) ] #最高位可能有进位,和数组设置多一位
for j in range(-1,-n-1,-1): #从后往前计算
x=(y+int(A[j])+int(B[j]))%10 #各位取余
y=int((y+int(A[j])+int(B[j]))/10) #各位进位
Sum[j]+=x
if j==-n:
Sum[j-1]=y #最高位
s=(str(i) for i in Sum)
s1=''.join(s) #列表转化为字符串
s2=s1.lstrip('0') #去除首位的0
print(int(s2))
十一、Huffman树
问题描述
本题任务:对于给定的一个数列,现在请你求出用该数列构造Huffman树的总费用。
例如,对于数列{pi}={5, 3, 8, 2, 9},Huffman树的构造过程如下:
1. 找到{5, 3, 8, 2, 9}中最小的两个数,分别是2和3,从{pi}中删除它们并将和5加入,得到{5, 8, 9, 5},费用为5。
2. 找到{5, 8, 9, 5}中最小的两个数,分别是5和5,从{pi}中删除它们并将和10加入,得到{8, 9, 10},费用为10。
3. 找到{8, 9, 10}中最小的两个数,分别是8和9,从{pi}中删除它们并将和17加入,得到{10, 17},费用为17。
4. 找到{10, 17}中最小的两个数,分别是10和17,从{pi}中删除它们并将和27加入,得到{27},费用为27。
5. 现在,数列中只剩下一个数27,构造过程结束,总费用为5+10+17+27=59。
输入格式
输入的第一行包含一个正整数n(n<=100)。
接下来是n个正整数,表示p0, p1, …, pn-1,每个数不超过1000。
输出格式
输出用这些数构造Huffman树的总费用。
样例输入
5
5 3 8 2 9
样例输出
59
def huffuman(L):
min1=min(L)
L.remove(min1)
min2=min(L)
L.remove(min2)
huff=min1+min2
return huff
n=int(input())
l1=list(input().split())
l1=list(map(int,l1))
X=[]
for i in range(len(l1)-1):
x=huffuman(l1)
X.append(x)
l1.append(x)
print(sum(X))
十二、2n皇后
问题描述
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入格式
输入的第一行为一个整数n,表示棋盘的大小。
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
输出一个整数,表示总共有多少种放法。
样例输入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
2
"""
Author:Lucky_bacon
Tool:Pycham、python3
"""
n = int(input())
mapL = [list(map(int, input().split())) for _ in range(n)] # 模拟棋盘
count = 0 # 计数器
def dfs(row, n, s, mapL):
global count
if row == n: # 判断是否是放完了最后一行,注意我的行数是从0开始,0代表第一行
if s == 2: # 2代表黑皇后,3代表白皇后
dfs(0, n, 3, mapL) # 黑皇后放完,开始放白皇后
if s == 3: # 全部放完
count += 1
return
#查看每一列的情况
for i in range(n):
if mapL[row][i] != 1: # 不为1、说明放了皇后,或者不能皇后
continue
if check(row, i, s, mapL):
mapL[row][i] = s # 可以放,将格子的数字变为放置对应皇后的数字
dfs(row + 1, n, s, mapL)#行数+1
mapL[row][i] = 1 # #统计过一次,开始回溯,重新开始计数
##查询对应位置是否存放黑白皇后
def check(row, j, s, mapL):
r = row - 1
k = j - 1
for i in range(row - 1, -1, -1): # 检查对应列
if mapL[i][j] == s:
return False
while r >= 0 and k >= 0: # 检查对应左上角
if mapL[r][k] == s:
return False
r -= 1
k -= 1
r = row - 1
k = j + 1
while r >= 0 and k < n: # 检查对应右上角
if mapL[r][k] == s:
return False
r -= 1
k += 1
return True
#def(a,b,c,d)
#a:所在行数;b:表示矩阵的大小 c:表示存放皇后的类型 d:表示当前矩阵
dfs(0, n, 2, mapL)
print(count)
十三、完美的代价
问题描述
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入格式
第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母
输出格式
如果可能,输出最少的交换次数。
否则输出Impossible
样例输入
5
mamad
样例输出
3
"""
Author:Lucky_bacon
Tool:Pycham、python3
"""
n = int(input())
st = list(input())
count = 0
j = 0
flag = 0
while len(st) > 1:
for i in range(len(st)-1,0,-1):
if st[i] == st[0]:
count += len(st)-1-i
st.pop(0)
j += 1
st.pop(i-1)
break
elif i == 1:
st.pop(0)
if n%2 == 0 or flag == 1:
print("Impossible")
exit()
count += n//2 -j
flag = 1
print(count)
【算法篇】
一、印章
问题描述
共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。
输入格式
一行两个正整数n和m
输出格式
一个实数P表示答案,保留4位小数。
n,m = map(int,input().split())
#定义一个二维列表,长度m+1
dp = [ [0 for i in range(m+1)] for j in range(m+1)]
for i in range(1,m+1):
for j in range(1,n+1):
if i < j:
dp[i][j] = 0
elif j == 1:
dp[i][j] = (1/n) ** (i-1)
else:
dp[i][j] = ( dp[i-1][j]) * (j*1.0/n) + (dp[i-1][j-1]) * (n-j+1)*1.0/n
s = float(dp[m][n])
print('%.4f'%s)
二、获取金币
样例输入
3
1 3 3
2 2 2
3 1 2
样例输出
11
分析:
1、看到矩阵,先联想下动态规划算法
在这里,直接在原矩阵的身上进行运算
一共分了两步:
①将矩阵的首行、首列相加起来
②对其他数字进行操作
n = int(input())
lst = []
for i in range(n):
lst.append(list(map(int,input().split())))
for i in range(1,n):
lst[0][i] += lst[0][i-1]
lst[i][0] += lst[i-1][0]
for i in range(1,n):
for j in range(1,n):
lst[i][j] += max(lst[i-1][j],lst[i][j-1])
print(lst[n-1][n-1])
三、数字游戏
给定一个1~N的排列a[i],每次将相邻两个数相加,得到新序列,再对新序列重复这样的操作,显然每次得到的序列都比上一次的序列长度少1,最终只剩一个数字。
例如:
3 1 2 4
4 3 6
7 9
16
样例输入
4 16
样例输出
3 1 2 4
分析:
1、为什么会联想到杨辉三角?
以3 1 2 4 5为例
继续试了下其他的列表:
n=3->1,2,1
n=4->1,3,3,1
2、核心:递归算法
def YanHui(x):
m = 1#记录列数
l1 = [1]
lst = []
while m<=x+1:
lst.append(l1)
l1 = [sum(t) for t in zip([0]+l1,l1+[0])]
m += 1
return lst[x]
def Search(n,m,re,lst,step,sum1,ru):
if step == n:
if sum1 == m:
print(str(re).strip('[]').replace(',',''))#re = [3,1,2,4]
ru[0] = 1#完成搜索
return 0
if not ru[0]:#搜索未成功
for i in range(1,n+1):#数字从1开始套
if ru[i] == 0:#判断是否用过
re[step] = i
ru[i] = 1
if sum1+re[step]*lst[step] <= m:#找规律,发现结果是符合杨辉三角
"""递归,
①从1开始寻找符合的元素列表,i =1 ,re = [1,.....]
②在每一个位置里,都开始寻找对应的数值
③当每找好一个数字,就开始判断step是否到n,总和是否为m,是的话就输出
④不是就继续查找
"""
Search(n, m, re, lst, step+1, sum1+re[step]*lst[step], ru)
ru[i] = 0#该位置不是这个数字,下一个
n,m = map(int,input().split())
re = [0 for _ in range(n)]#记录当前位置列表
lst = YanHui(n-1)
ru = [0 for _ in range(n+1)]#记录数字是否用过
Search(n,m,re,lst,0,0,ru)#第一个0表示获取数字的位置,第二个0表示相加总数
四、无聊的逗
问题描述
他拿出n个木棍,然后选出其中一些粘成一根长的,然后再选一些粘成另一个长的,他想知道在两根一样长的情况下长度最长是多少。
输入格式
第一行一个数n,表示n个棍子。第二行n个数,每个数表示一根棍子的长度。
输出格式
一个数,最大的长度。
样例输入
4
1 2 3 1
样例输出
3
运算思路
1、将列表分成若干个子列表
2、对于每一个子列表,进行求等和列表
n = int(input())
group = list(map(int,input().split()))
#将原本的列表分成若干个子列表
def SepList(group):
res = [[]]
for i in group:
res = res +[[i] + num for num in res]
return res
def CanPartition(lst):
sumLst = sum(lst)
target = sumLst // 2
#总和为奇数,凑不到两个列表是可以等和的
if sumLst % 2:
return False,target
dp = [False]*(target+1)
dp[0] = True
#设置dp[0]为True:方便下面的逻辑运算
for i in range(len(lst)):
for j in range(target,lst[i]-1,-1):
dp[j] = dp[j] or dp[j-lst[i]]
return dp[-1],target
lst = SepList(group)
max_length = 0#设置当前列表元素总和//2
#开始遍历所有子列表
for lst in lst:
if not lst:#lst为空,跳过
continue
flag, target = CanPartition(lst)#分裂等和子列表
"""
少了这一个条件的话,会出现两种情况
①flag=false,却可以输出
②flag为ture,但是target覆盖了最终答案
原因:子列表乱序
例如:
15
12 12 0 0 0 0 10 10 12 12 5 5 8 8 7"""
if flag and target>max_length:
max_length = target
print(max_length)
五、礼物
问题规则:
有个人要取走地上的石子,必须按照以下的规则去取。每次必须取连续的2*K个石子,并且满足前K个石子的重量和小于等于S,后K个石子的重量和小于等于S。由于时间紧迫,Jiaoshou只能取一次。
现在JiaoShou找到了聪明的你,问他最多可以带走多少个石子。
输入格式
第一行两个整数N、S。
第二行N个整数,用空格隔开,表示每个石子的重量。
输出格式
第一行输出一个数表示JiaoShou最多能取走多少个石子。
样列输入
8 3
1 1 1 1 1 1 1 1
样列输出
6
解题思路:
这道题目有四种解法:前缀树、二分法、贪心、滑动列表 一、滑动列表
def Solve(x):
pre, suffix = 0,0
k = 0
for j in range(x+1,n):
i = x
mid = j + i >> 1#右移一位
suffix += lst[j-1] +lst[j] -lst[mid]
pre += lst[mid]
while pre >s or suffix > s:
i += 2
mid = i+j >>1
pre = pre-lst[i-1]-lst[i-2] +lst[mid]
suffix -= lst[mid]
if suffix <= s:
k =max(k,j-i+1)
return k
n,s = map(int,input().split())
lst = []
lst.extend(list(map(int,input().split())))
ans = max(Solve(0),Solve(1))
lst.reverse()#翻转列表
ans = max(ans,Solve(0),Solve(1))#?
print(ans)
在这里通过是可以通过,但是。。。。不能运行10w以上的数据量,准确率20%。