藍橋杯模板(三)python組

taixian發表於2024-04-08

單調棧

#單調棧  -> 解決「下一個更大元素」,「上一個更小元素」
#注意1:找最近的比它小的數,需要維護單調遞增棧,即棧頂元素比它大的全部彈出(對於i+1來說,他們的貢獻不會比i大,所以沒用了)。棧頂剩下的就是最近那個。然後自己再入棧。
#注意2:找右邊最近的比它小的數,需要逆序遍歷。但棧依然是遞增的。
#注意4:一般棧裡是存下標。

#基本模板
def st(nums):
    st = []
    for num in  nums:
        while st and num >= st[-1]:  #遞增  <= 遞減
            st.pop()
        st.append(num)
#返回每一數下一個更大/小的數(list)
def n_st(nums):
    n = len(nums)
    res= [0]*n #存結果
    s = []
    for i in range(n-1,-1,-1): #正序遍歷 逆序遍歷都可  倒敘入棧==正序出棧
        while s and s[-1] <= num[i]:
             # 矮個起開,反正也被擋著了。。。
            s.pop()
        res[i] = s[-1] if s else -1
         # nums[i] 身後的更大元素
        s.append(nums[i])
    return s

單調佇列

#單調佇列  解決滑動視窗最值  

def wd(nums,k):
    ans = []
    q = deque() #使用雙端佇列
    for i in range(len(nums)):
        #1. 入 3.記錄答案
        while q and nums[q[i]] <= x:
            q.pop()
        q.append(i)
         #2.出
        if i-q[0] >= k: #視窗大小>= k
            q.popleft() #隊首移除視窗
        if i >= k-1:
            ans.append(nums[q[0]]) #(佇列遞減,隊首即最大值)
    return ans


#第二種

from collection import daque

def st(nums,k):
    win = deque()
    res= []
    for i in range(len(nums)):
        if i <k-1:
            win.append(nums[i])  # 先將視窗前 k - 1 填滿
        else:
             # 視窗開始向前滑動
            # 移入新元素
            win.append(nums[i])
             # 將當前視窗中的最大元素記入結果
            res.append(max(win))
            # 移出最後的元素
            win.popleft()
    return res

差分

#差分
#1.構建差分陣列
for i in range(len(s)-1,0,-1):
    s[i] -= s[i-1]

#2.轉換加減(區間加減->端點加減)
    s[l-1] += v
    s[r] -= v

#3.字首相加
for i in range(1,n):
    s[i] += s[i-1]

eg:
# https://www.lanqiao.cn/problems/1276/learning/

n,q = map(int,input().split())
a = [0]+list(map(int,input().split()))

b = [0]*(n+2)
for i in range(1,n+1):
    b[i] = a[i] - a[i-1]
    
for i in range(q):
    l,r,x = map(int,input().split())
    b[l] += x
    b[r+1] -= x

for i in range(1,n+1):
    a[i] = b[i] + a[i-1]
    if a[i] <= 0:
        print(0,end =' ')
    else:
        print(a[i],end = ' ')

並查集

#並查集

def find(x):
# 如果x不是根節點,則遞迴地找到x的根節點,並將x的父節點更新為根節點(實現狀態壓縮)

    if x!= p[x]:
        p[x] = find(p[x])
    return p[x]

for i in range(n):
    a,b = map(int,input().split())
    pa,pb = find(a),find(b)  # 分別找到a和b的根節點
    if pa != pb:
        p[pa] = pb

DFS

#深搜  1.確定dfs的兩個引數  2.確認終止條件 3.處理目前搜尋節點出發的路徑
ans = []
def dfs(層數,引數):
    if (出局判斷,特況):
        更新答案
    return   

    剪枝
    for (列舉下一層的情況):
        if (vis[i]==0):
            vis[i] = 1
            dfs(層數+1,引數)#下一層
            vis[i] = 0 #回覆狀態,不影響回溯時的使用 
            #有時候沒有顯式地使用棧和回溯操作,但實際上透過遞迴呼叫實現了DFS的功能(全球變暖問題,島嶼類)。

    return

BFS

from collections import deque, defaultdict

t = ''.join(['0', '1', '2', '3', '4', '5', '6', '7', '8', 'x'])  # 目標值
d = [-1, 1, -3, 3]  # 上下移 在陣列中步長為3
ls = ['0'] + list(map(str, input().split()))  # 輸入態
idx = ls.index('x')  # x的初始索引
#有時候需要加入falg變數 用於判斷符合
vis = defaultdict(int)  #判重陣列一定要有!!!
# 記錄已經訪問過的狀態,避免重複訪問同一個狀態

def bfs():
    q = deque()
    stp = 0  # 初始步數
    q.append([ls, idx, stp])

    s = ''.join(ls)
    vis[s] = 1
    res = -1  # 儲存最終的結果
    while q:
        ts, tidx, stp = q.popleft()
        if ''.join(ts) == t:  # 等於目標值
            res = stp
            break
        for i in d:
            tmp = ts.copy()  # 原始狀態的完整性,以便在搜尋失敗時回溯到上一個狀態
            nidx = tidx + i
            # 出界情況
            if nidx < 1 or nidx > 9: continue
            if (tidx == 3 or tidx == 6) and i == 1: continue
            if (tidx == 4 or tidx == 7) and i == -1: continue
            # 交換位置
            tmp[tidx], tmp[nidx] = tmp[nidx], tmp[tidx]
            stmp = ''.join(tmp)
            if vis[stmp]: continue
            vis[stmp] = 1
            q.append([tmp, nidx, stp + 1])
    print(res)

bfs()