基础算法
一、排序
1.冒泡排序
n=int(input())
a = list(map(int,input().split())
for i in range(n-1):
for j in range(i,n):
if a[i]>a[j]:
a[i],a[j]=a[j],a[i]
[宝藏排序1](蓝桥杯省赛无忧班(Python 组)第 3 期 - 宝藏排序I - 蓝桥云课 (lanqiao.cn))
2.选择排序
从左往右不断的找最小的值,往前交换
n = int(input())
a = list(map(int,input().split()))
for i in range(n-1):
min_value = a[i]
min_idx = i
for j in range(i,n):
if a[j]<min_value:
min_value = a[j]
min_idx = j
a[min_idx],a[i] = a[i],a[min_idx]
print(' '.join(map(str,a)))
[宝藏排序1](蓝桥杯省赛无忧班(Python 组)第 3 期 - 宝藏排序I - 蓝桥云课 (lanqiao.cn))
3.插入排序
从后往前找牌看看插到前面哪里好,就和打扑克牌边打牌边捯饬牌一样
n = int(input())
a = list(map(int,input().split()))
for i in range(1,n):
value = a[i]
insert_idx = 0
for j in range(i - 1,-1,-1):
if a[j] > value:
a[j+1]=a[j]
else:
insert_idx = j+1
break
a[insert_idx] = value
4.快速排序
-
设置基准下标,把比下标大的和小的分出来
-
左右递归排序
def partition(a,left,right):
idx = left+1
for i in range(left+1,right+1):
if a[i]<=a[left]:
a[i],a[idx]=a[idx],a[i]
idx += 1
a[left],a[idx-1] = a[idx-1],a[left]
def quicksort(a,left,right):
if left<right:
mid = partition(a,left,right)
quicksort(a,left,mid-1)
quicksort(a,mid+1,right)
5.归并排序
-
合并两个有序的列表
def Merge(A,B):
result = []
while len(A) != 0 and len(B) != 0:
if A[0] <= B[0]:
result.append(A.pop(0))
else:
result.append(B.pop(0))
result.extend(A)
result.extend(B)
return result
- 归并排序的步骤
-
把数组分成两部分
-
每部分递归处理变有序
-
将两个有序的列表合并起来
-
def MergeSort(A):
if len(A)<2:
return A
mid = len(A) // 2
left = MergeSort(A[:mid])
right = MergeSort(A[mid:])
return Merge(left,right)
6.桶排序
image-20240227210415300
def Bucket_Sort(a,bucketcount):
minvalue,maxvalue = min(a),max(a)
bucketsize = (maxvalue - minvalue + 1) // bucketcount
res = [[] for _ in range(bucketcount + 1)]
for x in a:
idx = (x-minvalue) // bucketsize
res[idx].append(x)
ans=[]
for res_x in res:
res_x.sort()
ans += res_x
retuen ans
7.经典练习
二、基础算法
1.枚举
逐个尝试所有可能的值来解决问题
2.模拟
——按题目含义模拟就行,一般不涉及算法
-
读懂题
-
代码和步骤一一对应
-
把重复的部分写成函数
-
按顺序写
ef next_step(x):
x = str(x)
next = 0
for i in range(len(x)):
next += int(x[i])
return next + int(x)
t = int(input())
result = []
for i in range(t):
n = int(input())
now_step = 1
step = 0
while now_step < n:
now_step = next_step(now_step)
step += 1
if now_step == n:
result.append(step)
else:
result.append(-1)
for i in range(len(result)):
print(result[i])
t = int(input())
ts = []
for i in range(t):
n = int(input())
a = list(map(int,input().split()))
count = 0
number1 = 0
number2 = 0
for j in range(n):
if a[j] < 0:
number1 += a[j]
elif a[j] > 0:
number2 += a[j]
else:
count += 1
if number2+count+number1==0:
ts.append(count+1)
else:
ts.append(count)
for i in range(len(ts)):
print(ts[i])
DNA序列修正(答案不是全对)
import os
import sys
import math
# 请在此输入您的代码
def judge(a,b):
if a=='A' and b=='T' or a=='T' and b=='A' or a=='C' and b=='G' or a=='G' and b=='C':
return True
else:
return False
N = int(input())
D1 = input()
D2 = input()
D3 = []
D4= []
D5 = []
count = 0
for i in range(N):
if judge(D2[i],D1[i]):
continue;
else:
if D1[i]==D2[i]:
D3.append(D1[i])
else:
D4.append(D1[i])
D5.append(D2[i])
A=D3.count('A')
T=D3.count('T')
C=D3.count('C')
G=D3.count('G')
length=len(D4)
for i in range(len(D4)):
for j in range(len(D5)):
if judge(D4[j],D5[j])!=True:
if judge(D4[i],D5[j])==True and judge(D4[j],D5[i])==True:
D5[i],D5[j] = D5[j],D5[i]
length-=2
count+=1
break
count+=abs(A-T)+abs(C-G)+min(A,T)+min(C,G)+count+length
print(int(count))
3.递归
-
自己调用自己
-
把大型复杂问题转为一个与原问题相似规模较小的问题
-
注意点:
-
写出口
-
将问题转为子问题
-
-
例子:阶乘
def f(n): if n<=1: return 1 ans = n * f(n-1) return ans
-
image-20240228175443069
def move(n,A,B,C): if n == 0: return #从A到B move(n-1,A,B,C) #从B到C move(n-1,B,A,C)
4.进制转换
-
基数:表示基本数字符号的个数
-
权:每个数字每位表示的数值 权=基数^x
-
按权展开法:11011=1^4+1^3.......
-
把K进制的数字转换为10进制的
int_to_char = '0123456789ABCDEF' char_to_int = {} for idx,chr in enumerate(int_to_char): char_to_int[chr] = idx def K_To_Ten(k,x): ans = 0 #翻转x x=x[::-1] for i in range(len(x)): ans = ans + char_to_int[x[i]] * k ** i return ans
-
十进制转其他(整数)
转小数
image-20240228193407280
int_to_char = '0123456789ABCDEF' char_to_int = {} for idx,chr in enumerate(int_to_char): char_to_int[chr] = idx def Ten_to_K(k,x): ans = '' while x!=0: ans += int_to_char[x % k] x//=k return ans[::-1]
5.前缀和
-
sum[i] = sum[i-1] + a[i]
-
能快速计算出区间
a[i] + a[i+1] + ... + a[j] = sum[j] - sum[i-1]
把复杂度从O(n)优化到了O(1)
6.差分
——提升修改的效率
-
image-20240228194406039
a[k] = d[1] + d[2] + ... + d[k]
a[]是D[]的前缀和
-
差分是前缀和的逆运算
-
尺取法:两个for循环变成一个,前提是两个变量之间是有关系的
-
习题:统计子矩阵
n,m,k=map(int,input().split()) a = [[0] for i in range(n)] a.insert(0,0*(m+1)) for i in range(1,n+1): a[i].extend(map(int,input().split())) s = [[0]*(m+1) for i in range(n+1)] for i in range(1,n+1): for j in range(1,m+1): s[i][j] = s[i-1][j] + a[i][j] ans = 0 for i1 in range(1,n+1): for i2 in range(i1,n+1): j1=1;z=0 for j2 in range(1,m+1): z += s[i2][j2] - s[i1-1][j2] while z>k: z -= s[i1][j1] - s[i1-1][j1] j1 += 1 ans += j2-j1+1 print(ans)
7.离散化
-
不关注数字本身,只关注大小关系,利用排名代替原数据
-
仅关注偏序的题都可以用离散化
-
步骤:
image-20240228194735069
def Discrete(a): #去重,排序 b = list(ser(a)) b.sort() dic = dict(zip(b,list(range(len(b))))) ans = [] for x in a: ans.append(dic[x]) return ans
8.贪心
-
image-20240228200123270
-
并不是所有的局部最优可以是全局最优
-
如何判断贪心:
image-20240228200611888
-
经典习题
-
[ ]
#导入堆的库 import heapq n = int(input()) a = list(map(int,input().split())) #堆:每次获取最小的元素,添加元素 #1. 把a转换成堆 heapq.heapqify(a) ans = 0 while len(a) >= 2: x = heapq.heappop(a) y = heapq.heappop(a) heapq.heappush(a,x+y) ans += x+y
-
[ ]
w = int(input()) n = int(input()) a = [] for i in range(n): a.append(int(input)) #1.排序 a.sort() #最小的和最大的下标 l,r = 0,n - 1 ans = 0 while True: if l==r: ans+=1 break if l>r: break if a[l] + a[r] <= w: ans+=1 l+=1 r-=1 else: ans+=1 r-+1 print(ans)
n,k = map(int,input().split()) a = list(map(int,input().split())) b = list(map(int,input().split())) cha = [] for i in range(len(a)): if b[i] - a[i] >0: cha.append(b[i] - a[i]) cha.sort(reverse=True) result = sum(a) if k >= len(cha): result += sum(cha) else: for i in range(k): result += cha[i] print(result)
n = int(input()) w = list(map(int,input().split())) result = 1000000 w.sort() i,j=0,1 while j<len(w): cha = abs(w[j]-w[i]) if cha < result: result=cha j+=1 i+=1 print(result)
-
-
9.双指针
-
[ ] 反向扫描
-
[ ] 滑动窗口
n,S = map(int,input().split()) a = list(map(int,input().split())) min_len() = n + 1 left,right=0,0 tot = 0 while left < n: #不断扩展右端点,直到区间和>S while right < n and tot < S: tot += a[right] right += 1 if tot >= S: min_len = min(min_len,right-left) #左端点往右走 tot -= a[left] left += 1 if min_len == n+1: min_len=0 print(min_len)
10.二分
-
每次将搜索范围缩小一半
-
二分的前提条件:单调性
-
步骤
-
找到区间
-
不断循环,直至区间满足特定的条件:计算中点或者随时调整
-
-
bitsect
模块(二分)-
insort_right(a,x)
插入 -
bisect_right(a,x)
查找
-
-
二分答案
image-20240229190645784
image-20240229190904925
11.倍增(快速幂)
-
高效求指数幂,基于分治的思想,通过反复求平方来实现快速计算指数幂处理二分,公共祖先
12.构造
-
通过观察规律和结构来解决方法
13.位运算
-
位运算:对二进制进行操作的运算方式
-
与运算:有0得0
-
或运算:有1得1
-
异或运算:相同为0,不同为1(考的概率大)^
-
取反 ~
-
左移,右移 << >>
每次向左移相当于×2,空缺的位置补0
每次右移相等于➗2,空缺的位置补0
-
-
位运算的技巧
image-20240229201002004