蓝桥杯python算法

嵌套数组

def tree(r):
    return [r,[],[]]
def insert_left(root,newnode):
    a=root.pop(1)
    if len(a)>=1:
        root.insert(1,[newnode,a,[]])
    else:
        root.insert(1,[newnode,[],[]])
def insert_right(root,newnode):
    a=root.pop(2)
    if len(a)>=1:
        root.insert(2,[newnode,[],a])
    else:
        root.insert(2,[newnode,[],[]])

a=tree(3)
insert_left(a,5)
insert_left(a,7)
insert_right(a,4)
insert_right(a,1)
print(a)

#[3, 
[7, 
    [5, [], []], 
    []], 
[1, 
    [], 
    [4, [], []]]]

链表存储

from collections import deque

class node:
    def __init__(self,elem):
        self.elem=elem
        self.lchild=None
        self.rchild=None

class tree:
    def __init__(self):
        self.root=None
    def add(self,elem):
        Node=node(elem)
        if self.root==None:
            self.root=Node
        else:
            queue=deque()
            queue.append(self.root)
            while queue:
                cnode=queue.popleft()
                if cnode.lchild==None:
                    cnode.lchild=Node
                    return
                else:
                    queue.append(cnode.lchild)
                if cnode.rchild==None:
                    cnode.rchild=Node
                    return
                else:
                    queue.append(cnode.rchild)

    #前序
    def pre(self,node):
        if node is None:
            return
        else:
            print(node.elem,end=' ')
            self.pre(node.lchild)
            self.pre(node.rchild)

Tree=tree()
for i in range(10):
    Tree.add(i)
Tree.pre(Tree.root)

0 1 3 7 8 4 9 2 5 6 

树状数组

下标从1开始

已知一个数组,求树状数组用在某个位置加上v的方法

a=[0]+[5,7,4,2] #下标必须从0开始
b=[0]*len(a)

def lowbit(n):
    return n & (-n)

#在i上加v
def add(i,v,b):
    while i<=n:
        b[i]+=v
        i+=lowbit(i)

#从第1个数字到到第i个数字        
def query(b,i):
    ans=0
    while i>0:
        ans+=b[i]
        i-=lowbit(i)
    return ans

b=[0]*(n+1)
#树状数组
for i in range(1,n+1):
    add(i,a[i],b)

BFS广度优先搜索

类似于树的层次搜索,答案不唯一

graph={"A":["B","C"],
       "B":["A","C","D"],
       "C":["A","B","E"],
       "D":["B","C","E"],
       "E":["C","D","F"],
       "F":["D","E"]}
def BFS(graph,start):
    queue=[]    用队列来存储,也可用双向队列deque() from collections import deque
    queue.append(start)
    s=set()    用集合来存储该点是否被访问了
    s.add(start)
    while len(queue)>0:
        a=queue.pop(0)
        print(a,end=' ')
        for i in graph[a]:
            if i not in s:
                queue.append(i)
                s.add(i)

BFS(graph,"C")

#C A B E D F

DFS深度优先搜索

用栈来存储,先进后出

#第二种方法建立一个parent字典存储访问某一个点前是访问哪一个点,就可以从任意一个点到任意点的路径

graph={"A":["B","C"],
       "B":["A","C","D"],
       "C":["A","B","E"],
       "D":["B","C","E"],
       "E":["C","D","F"],
       "F":["D","E"]}

def BFS(graph,start):
    stack=[]
    stack.append(start)
    s=set()
    s.add(start)
    #parent={start:None}

    while len(stack)>0:
        a=stack.pop()
        print(a,end=' ')
        for i in graph[a]:
            if i not in s:
                stack.append(i)
                s.add(i)
                #parent[i]=a
    #print(parent)
    #return parent

BFS(graph,"B")

'''
v="B"
while v!=None:
    print(v)
    v=parent[v]
'''
#B D E F C A 

Dijkstra算法

求解起始点到其他各点的最短距离

需要有一个元组记录一个点被访问的前一个点(parent),一个see集合记录已经访问过的点,一个距离元组记录开始点到各点的最短距离(distance)

用堆队列pqueue来更新起始点到其他各点的距离,堆队列能根据距离自动排序

import heapq #用堆存储,能够根据距离自动排序
import math

graph={"A":{"B":5,"C":1},
       "B":{"A":5,"C":2,"D":1},
       "C":{"A":1,"B":2,"E":8},
       "D":{"B":1,"C":4,"F":6},
       "E":{"C":8,"D":3},
       "F":{"D":6}}

def distan(graph,s):
    distance={s:0}
    for i in graph.keys():
        if i != s:
            distance[i]=math.inf
    return distance

def dijkstra(graph,s):
    parent={s:None}
    see=set()
    distance=distan(graph,s)
    pqueue=[]
    heapq.heappush(pqueue,(0,s)) #用堆压进去队列里,能够根据距离自动排序
    while len(pqueue)>0:
        a=heapq.heappop(pqueue)
        dis=a[0]
        see.add(a[1])
        node=graph[a[1]].keys()
        for i in node:
            if i not in see:
                if dis+graph[a[1]][i]<distance[i]:
                    heapq.heappush(pqueue,(dis+graph[a[1]][i],i))
                    parent[i]=a[1]
                    distance[i]=dis+graph[a[1]][i]
    return distance,parent
distance,parent=dijkstra(graph,"B")
print(distance)
print(parent)

#输出
{'B': 0, 'A': 3, 'C': 2, 'D': 1, 'E': 10, 'F': 7}
{'B': None, 'A': 'C', 'C': 'B', 'D': 'B', 'F': 'D', 'E': 'C'}

快速幂

以为例说明如何用倍增法做快速幂。
(1)a^11=a^(8+2+1),11的二进制为1101=2^3+2^2+2^0=8+4+1

(2)如何跳过那些没有的幂次?例如1011需要跳过。做个判断,用二进制的位运算实现:

n & 1      取n的最后一位,并且判断这一位是否需要跳过
n >>=1   把n右移一位,目的是把刚处理过的n的最后一位去掉。
取模a^n mod m=(a mod m)^n mod m

def quick(a,n):
    ans=1
    while n:
        if n&1:
            ans=ans*a
        a*=a #a^2,a^4....
        n>>=1
    print(ans)
    return ans

def quickmod(a,n,m):
    ans=1
    while n:
        if n&1:
            ans=(ans*a)%m
        a=a*a%m
        n>>=1
    print(ans)
    return ans

quick(2,10)
quickmod(2,10,3)

排序

选择排序

每次将最小的元素移到前边

def selectsort(a):
    for j in range(len(a)-1): #n个元素只需要进行n-1次
        for i in range(j+1,len(a)):
            if a[j]>a[i]:
                a[j],a[i]=a[i],a[j]
        print(a)
    return a
            
a=[8,5,6,4,3,7,10,2]
selectsort(a)

输出
[2, 8, 6, 5, 4, 7, 10, 3]
[2, 3, 8, 6, 5, 7, 10, 4]
[2, 3, 4, 8, 6, 7, 10, 5]
[2, 3, 4, 5, 8, 7, 10, 6]
[2, 3, 4, 5, 6, 8, 10, 7]
[2, 3, 4, 5, 6, 7, 10, 8]
[2, 3, 4, 5, 6, 7, 8, 10]

冒泡排序

相邻两两进行比较,将最大的数一直移到最后面

def maopaosort(a):
    for j in range(len(a)-1,0,-1): #n个数只需要进行n-1次
        for i in range(j):
            if a[i]>a[i+1]:
                a[i],a[i+1]=a[i+1],a[i]
        print(a)
    return a
              
a=[8,5,6,4,3,7,10,2]
maopaosort(a)

输出
[5, 6, 4, 3, 7, 8, 2, 10]
[5, 4, 3, 6, 7, 2, 8, 10]
[4, 3, 5, 6, 2, 7, 8, 10]
[3, 4, 5, 2, 6, 7, 8, 10]
[3, 4, 2, 5, 6, 7, 8, 10]
[3, 2, 4, 5, 6, 7, 8, 10]
[2, 3, 4, 5, 6, 7, 8, 10]

归并排序

分组,每组进行比较,直到所有有序

例如:[8,5,6,4,3,7,10,2]

           [8,5,6,4] [3,7,10,2]

           [8,5][6,4][3,7][10,2]

不能再继续分下去(start=end),则对他们进行排序,再两两合并

def merge(a,start,mid,end):
    temp=[]
    i=start
    j=mid+1
    while i<=mid and j<=end:
        if a[i]>a[j]:
            temp.append(a[j])
            j+=1
        else:
            temp.append(a[i])
            i+=1
    temp.extend(a[i:mid+1])
    temp.extend(a[j:])
    for i in range(start,end+1):
        a[i]=temp[i-start]
        #从后面的半部分开始时需要结合start将temp赋值给a中的i位置
    print(a)
    return a

def metgesort(a,start,end):
    if start==end:
        return
    mid=(start+end)//2
    metgesort(a,start,mid)
    metgesort(a,mid+1,end)
    merge(a,start,mid,end)
    
a=[8,5,6,4,3,7,10,2]
metgesort(a,0,7)

输出
[5, 8, 6, 4, 3, 7, 10, 2]
[5, 8, 4, 6, 3, 7, 10, 2]
[4, 5, 6, 8, 3, 7, 10, 2]
[4, 5, 6, 8, 3, 7, 10, 2]
[4, 5, 6, 8, 3, 7, 2, 10]
[4, 5, 6, 8, 2, 3, 7, 10]
[2, 3, 4, 5, 6, 7, 8, 10]

插入排序

对于前面 j-1个元素有序,将a[j]与前 j-1个元素进行比较并插入,使用复制替换

def insertsort(a,j):
    for i in range(j):
        if a[i]>a[j]:
            a[i],a[j]=a[j],a[i]
    print(a)
    return a
              
a=[8,5,6,4,3,7,10,2]
for i in range(1,len(a)):
    insertsort(a,i)

输出
[5, 8, 6, 4, 3, 7, 10, 2]
[5, 6, 8, 4, 3, 7, 10, 2]
[4, 5, 6, 8, 3, 7, 10, 2]
[3, 4, 5, 6, 8, 7, 10, 2]
[3, 4, 5, 6, 7, 8, 10, 2]
[3, 4, 5, 6, 7, 8, 10, 2]
[2, 3, 4, 5, 6, 7, 8, 10]

桶排序

将元素按大小分别放在几个桶里,对桶内元素进行排序,再从第1个桶开始合并桶里排列好的数据

import math

def selectsort(a):
    for j in range(len(a)-1):
        for i in range(j,len(a)):
            if a[i]<a[j]:
                a[i],a[j]=a[j],a[i]
    return a

def bucketsort(a):
    maxA=max(a)
    minA=min(a)
    temp=[[],[],[]]
    bucketgroup=3 #桶的个数
    innumber=math.ceil((maxA-minA)/bucketgroup) #每个桶的元素数量max

    for i in a:
        j=(i-minA)//innumber #应该放在哪一个桶里
        temp[j].append(i)
    print(temp) #输出每个桶分配的元素情况
        
    result=[]   
    for i in range(bucketgroup):
        b=selectsort(temp[i])
        result.extend(b)
    print(result)
    return result
              
a=[8,5,6,4,3,7,10,2]
bucketsort(a)

[[4, 3, 2], [5, 6, 7], [8, 10]] 
[2, 3, 4, 5, 6, 7, 8, 10]

计数排序

需要一个计数器来记录数组中的元素个数,元素范围为 [1,9]

def countsort(a):
    n=len(a)
    maxa=max(a)
    count1=[0]*(maxa+1)
    for i in a:
        count1[i]+=1
    print(count1)  #打印计数器
    temp=[]
    for i in range(1,maxa+1):
        if count1[i]>0:
            temp.extend([i]*count1[i])
    print(temp)
              
a=[8,5,6,4,2,7,7,2]
countsort(a)

输出
[0, 0, 2, 0, 1, 1, 1, 2, 1] #计数器
[2, 2, 4, 5, 6, 7, 7, 8]

基数排序

类似于桶排序,建立9个桶,分别先对个位数进行分类,再依次输出,再对十,百...位进行分类,直到最大的那一位

def radixsort(a):
    base=1
    maxa=max(a)
    while base<maxa:
        count1=[] #创建计数器
        for i in range(10):
            count1.append([])
        #分类
        for num in a:
            j=num//base%10
            count1[j].append(num)
        #输出
        temp=[]
        for k in range(10):
            if count1[k]:
                temp.extend(count1[k])
        a=temp
        base*=10
        print(a)     
              
a=[81,587,674,4475,2235,774,745,4212]
radixsort(a)

输出
[81, 4212, 674, 774, 4475, 2235, 745, 587]
[4212, 2235, 745, 674, 774, 4475, 81, 587]
[81, 4212, 2235, 4475, 587, 674, 745, 774]
[81, 587, 674, 745, 774, 2235, 4212, 4475]

ST表

用于求区间的最值

import math

#ST表的创建
def st(arr):
    n=len(arr)
    m=int(math.log(n,2))+1
    ST=[[0]*m for i in range(n)]  #ST[i][j]表示左端点为i,长度为2^j区间的最值,也就是[i,i+2^j-1]
    for i in range(n):
        ST[i][0]=arr[i]
    for j in range(1,m):
        for i in range(n):
            if i+2**j-1<n:
                ST[i][j]=max(ST[i][j-1],ST[i+2**(j-1)][j-1])
    return ST

#求某个区间的最值
def query(ST,l,r):
    x=int(math.log(r-l+1,2))
    print(max(ST[l][x],ST[r-2**x+1][x]))
    return max(ST[l][x],ST[r-2**x+1][x]) #将区间拆成长度相同的两段
    
arr=[9,3,1,7,5,6,0,8]            
ST=st(arr)
print(ST)
query(ST,2,7)

0-1背包问题

也就是在容量为M的背包里,放入n种物品(第i种物品的重量为wi,价值为vi),使得价值最大,每一种物品只有一个

二维数组

m=10 #背包重量
n=4 #物品
a=[[0,0],[2,1],[3,3],[4,5],[7,9]]
dp=[[0]*(m+1) for i in range(n+1)]  dp[i][j]为第i种物品在容量为j时的最大价值
print(dp)
for i in range(n+1):
    for j in range(m+1):
        if i==0 or j==0:
            dp[i][j]=0  
        else:
            if a[i][0]>j:
                dp[i][j]=dp[i-1][j]  不拿
            else:
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-a[i][0]]+a[i][1])  拿
print(dp)

输出
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], 
 [0, 0, 1, 3, 3, 4, 4, 4, 4, 4, 4],
 [0, 0, 1, 3, 5, 5, 6, 8, 8, 9, 9],
 [0, 0, 1, 3, 5, 5, 6, 9, 9, 10, 12]]

一维滚动数组

m=10 #背包重量
n=4 #物品
a=[[0,0],[2,1],[3,3],[4,5],[7,9]]    d[j]表示容量为j时价值最大为多少
dp=[0]*(m+1)
for i in range(1,n+1):
    for j in range(m,a[i][0]-1,-1):  从尾开始填充
        if a[i][0]<=j:
            dp[j]=max(dp[j],dp[j-a[i][0]]+a[i][1])
print(dp)

输出
[0, 0, 1, 3, 5, 5, 6, 9, 9, 10, 12]

完全背包问题

与0-1背包问题不同的是,物品的数量是无限的

m=10 #背包重量
n=4 #物品
a=[[0,0],[2,1],[3,3],[4,6],[8,10]]
dp=[[0]*(m+1) for i in range(n+1)]
print(dp)
for i in range(n+1):
    for j in range(m+1):
        if i==0 or j==0:
            dp[i][j]=0
        else:
            dp[i][j]=dp[i-1][j]  #继承上一层的状态
            if a[i][0]<=j:
                dp[i][j]=max(dp[i][j],dp[i][j-a[i][0]]+a[i][1])
print(dp)

输出
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5],
 [0, 0, 1, 3, 3, 4, 6, 6, 7, 9, 9],
 [0, 0, 1, 3, 6, 6, 7, 9, 12, 12, 13],
 [0, 0, 1, 3, 6, 6, 7, 9, 12, 12, 13]]

滚动数组

m=10 #背包重量
n=4 #物品
a=[[0,0],[2,1],[3,3],[4,6],[8,10]]
dp=[0]*(m+1)
print(dp)
for i in range(1,n+1):
    for j in range(a[i][0],m+1):
        dp[j]=max(dp[j],dp[j-a[i][0]]+a[i][1])
print(dp)

输出
[0, 0, 1, 3, 6, 6, 7, 9, 12, 12, 13]

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值