AcWing--數據結構1

用數組來模擬鏈表。這種實現鏈表的方式也叫靜態鏈表

1.單鏈表

寫鄰接表:存儲圖和樹

我們定義:e[N]用來表示某個點的是多少;ne[N]用來表示某個點的next指針是多少

e和ne是用下標關聯起來的

如:head->3->5->7->9->空(下標從0開始,3的下標是0,以此類推,空的下標為-1)

那么e[0]=3,ne[0]=1;e[1]=5,ne[1]=2;...e[3]=9,ne[3]=-1

?
//單鏈表模板//head指頭指針(頭指針指向頭結點),e[head]指的是頭結點的值
//idx指的是下一個可存儲的位置的索引,也可以說是插入的第幾個數的序號,即idx=0時表示插入的第一個數,其實就是存儲當前已經用到的點
int head,idx;int e[N],ne[N];    //e[N]存儲的是結點的值,ne[N]存儲的是結點的下一個結點的索引 //初始化
void init(){head = -1;//頭指針默認賦-1 idx = 0;
}//將x點插入頭結點
void insert_to_head(int x){e[idx] = x;
//將要插入的點的下一個指針指向head指向的點ne[idx] = head;
//將head指向新點,并idx指向下一個位置head = idx++;
}//將k后面的點刪除
void remove(int k){ne[k] = ne[ne[k]];
}//將x點插入下標為k的點后面
void insert(int k ,int x){e[idx] = x;
//將x點指向k指向的點ne[idx] = ne[k];
//將k指向x點,并idx向后走ne[k] = idx++;
}?

#include<iostream>using namespace std;const int N = 1e5+10;int head,idx;//head指頭指針(頭指針指向頭結點),e[head]指的是頭結點的值
//idx指的是下一個可存儲的位置的索引,也可以說是插入的第幾個數的序號,即idx=0時表示插入的第一個數int e[N],ne[N];//e[N]存儲的是結點的值,ne[N]存儲的是結點的下一個結點的索引 void init(){head = -1;//head的默認值賦-1 idx = 0;
}void insert_to_head(int x){e[idx] = x;ne[idx] = head;head = idx++;
}void remove(int k){ne[k] = ne[ne[k]];
}void insert(int k ,int x){e[idx] = x;ne[idx] = ne[k];ne[k] = idx++;
}int main(){int m;cin>>m;init();while(m--){char op;int k,x;cin>>op;
//頭結點if(op == 'H'){cin>>x;insert_to_head(x);}else if(op == 'I'){//插入cin>>k>>x;insert(k-1,x);//第k個插入的數索引為k-1,因為idx是從0開始的,第一個插入的數索引為1;}else{//刪K后cin>>k;if(!k) head = ne[head];else remove(k-1);}}for(int i = head ; i != -1 ; i = ne[i]) cout<<e[i]<<" ";cout<<endl;return 0;
} 

2.雙鏈表

我們定義:e[N]:當前結點的值是多少;l[N]:當前結點左邊是誰;r[N]:當前結點右邊是誰

并且令下標為0的點是head,下標為1的點是最后一個點

//雙鏈表模板
int l[N],r[N],e[N];
int idx;
//初始化
void init(){//頭結點指向尾結點,尾結點指向頭節點,頭結點指針為0,尾結點指針為1,所以頭指針為1,尾指針為0r[0] = 1;l[1] = 0;idx = 2; //從2開始
}
//插入,在k的右邊插入x
void insert(int k, int x){e[idx] = x;//賦值
//先將k的兩邊分別指向原來鏈表l[idx] = k;r[idx] = r[k];
//改變原鏈表的指向l[r[k]] = idx;//必須這步在前面,否則r[k]的值會被修改 r[k] = idx++;
}//在K的左邊插入,也可以直接調用,insert(l[k],x)
//刪除第k個點,k右邊的左邊等于K的左邊,K的左邊的右邊等于k的右邊
void remove(int k){r[l[k]] = r[k];l[r[k]] = l[k];
}

?

#include <iostream>
using namespace std;const int N=100010;
int idx,e[N],l[N],r[N];void init(){//0表示左端點//1表示右端點//虛擬頭和虛擬尾l[0]=-1,r[0]=1,l[1]=0,r[1]=-1;idx=2;
}
//最左端插入
void insertLeft(int x){e[idx]=x;r[idx]=r[0];l[idx]=0;l[r[0]]=idx;r[0]=idx;idx++;
}
//最右端插入
void insertRight(int x){e[idx]=x;r[idx]=1;l[idx]=l[1];r[l[1]]=idx;l[1]=idx;idx++;
}void insert_left_k(int k,int x){e[idx]=x;r[idx]=k;l[idx]=l[k];r[l[k]]=idx;l[k]=idx;idx++;
}void insert_right_k(int k,int x){e[idx]=x;r[idx]=r[k];l[idx]=k;l[r[k]]=idx;r[k]=idx;idx++;
}
//刪除第k個插入點
void remove(int k){l[r[k]]=l[k];r[l[k]]=r[k];
}int main(){int m;cin>>m;init();int k,x;string s;while(m--){cin>>s;if(s[0]=='L'){cin>>x;insertLeft(x);}else if(s[0]=='R'){cin>>x;insertRight(x);}else if(s[0]=='D'){cin>>k;remove(k+1);}else if(s[0]=='I' && s[1]=='L'){cin>>k>>x;insert_left_k(k+1,x);}else{cin>>k>>x;insert_right_k(k+1,x);}}for(int i=r[0];i!=1;i=r[i]) cout<<e[i]<<" ";cout<<endl;return 0;
}

棧和隊列

棧:后進先出

隊列:先進先出

AcWing 828. 模擬棧

?//棧模板
// tt表示棧頂
int stk[N], tt;

// 向棧頂插入一個數
stk[ ++ tt]?= x;

// 從棧頂彈出一個數,刪除
tt?-- ;

// 棧頂的值
stk[tt];

// 判斷棧是否為空,如果 tt?>= 0,則表示不為空
if (tt?>= 0) not empty

else empty

#include <iostream>
using namespace std;const int N=100010;
//tt是棧頂指針
int stk[N],tt;void push(int x){stk[tt]=x;tt++;
}void pop(){tt--;
}bool empty(){if(tt==0) return true;else return false;
}int query(){if(!empty()) return stk[tt-1];
}int main(){tt=0;int m;cin>>m;string s;int x;while(m--){cin>>s;if(s=="push"){cin>>x;push(x);}else if(s=="pop"){pop();}else if(s=="empty"){bool tmp=empty();if(tmp) cout<<"YES"<<endl;else cout<<"NO"<<endl;}else{cout<<query()<<endl;}}return 0;
}

AcWing 829. 模擬隊列?

//模擬普通隊列模板

// hh 表示隊頭,tt表示隊尾
int q[N], hh = 0, tt = -1;

// 向隊尾插入一個數
q[ ++ tt] = x;

// 從隊頭彈出一個數
hh ++ ;

// 隊頭的值
q[hh];

// 判斷隊列是否為空,如果 tt >= hh,則表示不為空
if (tt >= hh) not empty

else empty

//模擬循環隊列模板

// hh 表示隊頭,tt表示隊尾的后一個位置
int q[N], hh = 0, tt = 0;

// 向隊尾插入一個數
q[tt ++ ] = x;
if (tt == N) tt = 0;

// 從隊頭彈出一個數
hh ++ ;
if (hh == N) hh = 0;

// 隊頭的值
q[hh];

// 判斷隊列是否為空,如果hh != tt,則表示不為空(其實不能這樣簡單判斷是否為空)
if (hh != tt)
{

}

?單調棧?

一般問題:給定一個序列,求序列中的每一個數左邊離它最近的且比它小的數在什么地方

//單調棧常見模型:找出每個數左邊離它最近的比它大/小的數
int top = -1;
while(n--)
{
? ? while (top >= 0 && check(stk[top], x)) top -- ;
? ? stk[ ++ top] = x;
}

?

//暴力做法,兩重循環
for(int i=0;i<n;i++){
?? ?for(int j=i-1;j>=0;j--){
?? ??? ?if(a[i]>a[j]){
?? ??? ??? ?cout<<a[j]<<endl;
?? ??? ??? ?break;
?? ??? ?}
?? ?}
}

?找性質:如果棧中兩個數,ai,aj存在:ai>=aj并且i<j,則ai可以刪除,這樣刪完后棧中嚴格單調。

這樣我們從單調棧的棧頂元素開始查找,如果棧頂元素大于等于a[i],那么我們將其刪掉,直到棧頂元素小于a[i],我們將其作為答案輸出,并把a[i]放進棧中。

#include <iostream>
using namespace std;
const int N = 100010;int stk[N];
int tt = -1;int main(){int n;cin>>n;while(n--){int x;cin>>x;while(tt >= 0 && stk[tt] >= x) tt--;//比x大的元素全彈出來 if(tt >= 0) cout<<stk[tt]<<" ";//彈完之后如果還有元素就輸出棧頂元素 else cout<<-1<<" ";//無就輸出-1 stk[++tt] = x;//最后要把x存入,因為x是有可能比之后的元素小的,并且x離之后的元素最近 }return 0;
}

單調隊列

常見用途:求滑動窗口里的最大值或最小值

//單調隊列常見模型:
int hh = 0, tt = -1;
for (int i = 0; i < n; i ++ )
{
? ? while (hh <= tt && check_out(q[hh])) hh ++ ; ?// 判斷隊頭是否滑出窗口
? ? while (hh <= tt && check(q[tt], i)) tt -- ;
? ? q[ ++ tt] = i;
}

?

隨著窗口的移動,每次在隊尾插入新元素,同時在隊頭彈出已經不在窗口里的元素,始終保證隊列的長度等于窗口里元素的個數。?

暴力做法:遍歷整個隊列,找到最小值/最大值。o(nk)

優化(最小值舉例):

????????只要隊列里有前面一個數比后面一個數大,那前面的那個數就完全沒有用。我們把所有在前面的大的數刪掉后,整個序列就是一個單調遞增的序列。在單調遞增的序列里找最小值只需要找最左邊的端點,即隊頭。

最大值的做法和上面找最小值的做法類似

tips:隊列中存儲的是下標

#include <iostream>using namespace std;const int N = 1000010;int a[N],q[N];//q[N]存的是下標 int main(){int n,k;cin>>n>>k;for(int i = 0; i< n ; i++) cin>>a[i];//最小值 int hh = 0, tt = -1;for(int i = 0 ; i < n; i++){//滑出隊頭 if(hh <= tt && q[hh] < i-k+1) hh++;//i-k+1為窗口的最左端索引//去掉比當前要進入的數更大的數 while(hh <= tt && a[q[tt]] >= a[i]) tt--;//當前操作數的索引存入數組 q[++tt] = i;// i 等于 k - 1 時,窗口的大小剛好為 k。因此,當 i 大于或等于 k - 1 時,窗口就已經包含了至少 k 個元素。if(i >= k-1) cout<<a[q[hh]]<<" ";}cout<<endl;//最大值,除a[q[tt]] <= a[i]外無變化 hh = 0, tt = -1;for(int i = 0 ; i < n; i++){if(hh <= tt && q[hh] < i-k+1) hh++;while(hh <= tt && a[q[tt]] <= a[i]) tt--;q[++tt] = i;if(i >= k-1) cout<<a[q[hh]]<<" ";}cout<<endl;return 0;
}

KMP

問題:需要在一個極長的字符串中匹配一個短字符串,比如各種文本編輯器里的查找功能。

即在母串中找到第一次出現完整子串時的起始位置。

我們將母串寫為S,模式串寫為P

暴力做法:

我們設置一個i指針指向母串和一個j指針指向模式串

當i指針和j指針指向的字符相等時,就同時后移一位;

當i指針和j指針指向的字符不相等時,就將i指針回溯到i-j+1的位置,j指針設置為0,重復匹配的過程,直到到達模式串的末尾,我們認為匹配成功

在最壞的情況下,這個算法的時間復雜度為O(mn),m為母串的長度,n為模式串的長度

優化:利用已經部分匹配這個有效信息,保持i指針不回溯,通過修改j指針,讓模式串盡量地移動到有效的位置

當匹配失敗時,我們將j指針移動到第k位,其中k的性質是:模式串P的第0位到第k-1位的串和母串T的i

指針前面的串盡可能地相等,即 T[i-k ~ i-1] == P[0 ~ k-1]

如果我們仔細觀察,又能發現 P[0 ~ k-1] == P[j-k ~ j-1],也就是前綴和后綴相同。

為了能找到j指針回退的位置,我們預處理出來一個數組,稱為next數組,也被稱為部分匹配表

next數組的值就表示:當主串與模式串的某一位字符不匹配時,模式串要回退的位置

手動模擬求next數組:

對 p = “abcab”

? ? p?? ?a?? ?b?? ?c?? ?a?? ?b
下標?? ?1?? ?2?? ?3?? ?4?? ?5
next[]?? ?0?? ?0?? ?0?? ?1?? ?2
對next[ 1 ] :前綴 = 空集—————后綴 = 空集—————next[ 1 ] = 0;

對next[ 2 ] :前綴 = { a }—————后綴 = { b }—————next[ 2 ] = 0;

對next[ 3 ] :前綴 = { a , ab }—————后綴 = { c , bc}—————next[ 3 ] = 0;

對next[ 4 ] :前綴 = { a , ab , abc }—————后綴 = { a . ca , bca }—————next[ 4 ] = 1;

對next[ 5 ] :前綴 = { a , ab , abc , abca }————后綴 = { b , ab , cab , bcab}————next[ 5 ] = 2;

?// s[]是長文本,p[]是模式串,m是s的長度,n是p的長度
//求模式串的Next數組:
for (int i = 2, j = 0; i <= n; i ++ )
{?? ?
? ? while (j && p[i] != p[j + 1]) j = ne[j];
? ? if (p[i] == p[j + 1]) j ++ ;
? ? ne[i] = j;
}

// 匹配
for (int i = 1, j = 0; i <= m; i ++ )
{
? ? while (j && s[i] != p[j + 1]) j = ne[j];
? ? if (s[i] == p[j + 1]) j ++ ;
? ? if (j == n)
? ? {
? ? ? ? j = ne[j];
? ? ? ? // 匹配成功后的邏輯
? ? }
}

//KMP算法即字符串匹配算法
#include <iostream>using namespace std;const int N = 10010, M = 100010;//p,s,ne數組索引都是從1開始的 
char p[N],s[M];
int ne[N];int main(){                   int n,m;cin>>n>>p+1>>m>>s+1;//	//輸出為空 
//	cout<<p<<endl;
//	cout<<s<<endl;
//	//輸出整個p和整個s 
//	cout<<p+1<<endl;
//	cout<<s+1<<endl;//求ne數組的過程,ne[1]為0,所以從2開始,ne[i]表示從1到i之間,前綴和后綴最長相等元素的長度//next數組的求法是模板串自己與自己進行匹配 for(int i = 2, j = 0; i <= n; i++){//如果不等就回溯while(j && p[i] != p[j+1]) j = ne[j];//如果相等,模板串下標j的元素是提前和文本串對應j的下一個元素也就是下標為i的元素比較,所以j要+1if(p[i] == p[j+1]) j++;//現在j就已經是前綴和后綴最長相等元素的長度,所以要賦給ne[i]ne[i] = j;}//kmp匹配過程,模板串與文本串進行匹配 for(int i = 1, j = 0; i <= m; i++){//如果不等就回溯while(j && s[i] != p[j+1]) j = ne[j];//如果相等,模板串下標j的元素是提前和文本串對應j的下一個元素也就是下標為i的元素比較,所以j要+1(短的為模板串)if(s[i] == p[j+1]) j++;//j == n是找到了完整的相同的字符串if(j == n){cout<<i-n<<" ";//輸入匹配完全的字符串的頭下標,題目下標是從0開始的,所以不用加一 j = ne[j];//繼續回溯找下一個相同的字符串,不要從頭開始}}return 0; 
}

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/84350.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/84350.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/84350.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

云啟出海,智聯未來|阿里云網絡「企業出海」系列客戶沙龍上海站圓滿落地

借阿里云中企出海大會的東風&#xff0c;以**「云啟出海&#xff0c;智聯未來&#xff5c;打造安全可靠的出海云網絡引擎」為主題的阿里云企業出海客戶沙龍云網絡&安全專場于5.28日下午在上海順利舉辦&#xff0c;現場吸引了來自攜程、小紅書、米哈游、嗶哩嗶哩、波克城市、…

多模態分類案例實現

以下是基于飛槳平臺實現的多模態分類詳細案例&#xff0c;結合圖像和文本信息進行分類任務。案例包含數據處理、模型構建、訓練和評估的完整流程&#xff0c;并提供詳細注釋&#xff1a; 一、多模態分類案例實現 import os import json import numpy as np from PIL import I…

Express框架:Node.js的輕量級Web應用利器

Hi,我是布蘭妮甜 !在當今快速發展的Web開發領域,Node.js已成為構建高性能、可擴展網絡應用的重要基石。而在這片肥沃的生態系統中,Express框架猶如一座經久不衰的燈塔,指引著無數開發者高效構建Web應用的方向。本文章在為讀者提供一份全面而深入的Express框架指南。無論您…

K-Means顏色變卦和漸變色

一、理論深度提升&#xff1a;補充算法細節與數學基礎 1. K-Means 算法核心公式&#xff08;增強專業性&#xff09; 在 “原理步驟” 中加入數學表達式&#xff0c;說明聚類目標&#xff1a; K-Means 的目標是最小化簇內平方和&#xff08;Within-Cluster Sum of Squares, W…

深入解析C#表達式求值:優先級、結合性與括號的魔法

—— 為什么2/6*4不等于1/12&#xff1f; &#x1f50d; 一、表達式求值順序為何重要&#xff1f; 表達式如精密儀器&#xff0c;子表達式求值順序直接決定結果。例如&#xff1a; int result 3 * 5 2;若先算乘法&#xff1a;(3*5)2 17 ?若先算加法&#xff1a;3*(52)21…

Docker 離線安裝指南

參考文章 1、確認操作系統類型及內核版本 Docker依賴于Linux內核的一些特性&#xff0c;不同版本的Docker對內核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux內核3.10及以上版本&#xff0c;Docker17.09及更高版本對應Linux內核4.9.x及更高版本。…

Spring——Spring相關類原理與實戰

摘要 本文深入探討了 Spring 框架中 InitializingBean 接口的原理與實戰應用&#xff0c;該接口是 Spring 提供的一個生命周期接口&#xff0c;用于在 Bean 屬性注入完成后執行初始化邏輯。文章詳細介紹了接口定義、作用、典型使用場景&#xff0c;并與其他相關概念如 PostCon…

Angular微前端架構:Module Federation + ngx-build-plus (Webpack)

以下是一個完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 實現了主應用&#xff08;Shell&#xff09;與子應用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;? 項目結構 angular-mf/ ├── shell-app/ # 主應用&…

ESP32 I2S音頻總線學習筆記(四): INMP441采集音頻并實時播放

簡介 前面兩期文章我們介紹了I2S的讀取和寫入&#xff0c;一個是通過INMP441麥克風模塊采集音頻&#xff0c;一個是通過PCM5102A模塊播放音頻&#xff0c;那如果我們將兩者結合起來&#xff0c;將麥克風采集到的音頻通過PCM5102A播放&#xff0c;是不是就可以做一個擴音器了呢…

馮諾依曼架構是什么?

馮諾依曼架構是什么&#xff1f; 馮諾依曼架構&#xff08;Von Neumann Architecture&#xff09;是現代計算機的基礎設計框架&#xff0c;由數學家約翰馮諾依曼&#xff08;John von Neumann&#xff09;及其團隊在1945年提出。其核心思想是通過統一存儲程序與數據&#xff0…

【持續更新】linux網絡編程試題

問題1 請簡要說明TCP/IP協議棧的四層結構&#xff0c;并分別舉出每一層出現的典型協議或應用。 答案 應用層&#xff1a;ping,telnet,dns 傳輸層&#xff1a;tcp,udp 網絡層&#xff1a;ip,icmp 數據鏈路層&#xff1a;arp,rarp 問題2 下列協議或應用分別屬于TCP/IP協議…

橢圓曲線密碼學(ECC)

一、ECC算法概述 橢圓曲線密碼學&#xff08;Elliptic Curve Cryptography&#xff09;是基于橢圓曲線數學理論的公鑰密碼系統&#xff0c;由Neal Koblitz和Victor Miller在1985年獨立提出。相比RSA&#xff0c;ECC在相同安全強度下密鑰更短&#xff08;256位ECC ≈ 3072位RSA…

【JVM】- 內存結構

引言 JVM&#xff1a;Java Virtual Machine 定義&#xff1a;Java虛擬機&#xff0c;Java二進制字節碼的運行環境好處&#xff1a; 一次編寫&#xff0c;到處運行自動內存管理&#xff0c;垃圾回收的功能數組下標越界檢查&#xff08;會拋異常&#xff0c;不會覆蓋到其他代碼…

React 基礎入門筆記

一、JSX語法規則 1. 定義虛擬DOM時&#xff0c;不要寫引號 2.標簽中混入JS表達式時要用 {} &#xff08;1&#xff09;.JS表達式與JS語句&#xff08;代碼&#xff09;的區別 &#xff08;2&#xff09;.使用案例 3.樣式的類名指定不要用class&#xff0c;要用className 4.內…

Linux鏈表操作全解析

Linux C語言鏈表深度解析與實戰技巧 一、鏈表基礎概念與內核鏈表優勢1.1 為什么使用鏈表&#xff1f;1.2 Linux 內核鏈表與用戶態鏈表的區別 二、內核鏈表結構與宏解析常用宏/函數 三、內核鏈表的優點四、用戶態鏈表示例五、雙向循環鏈表在內核中的實現優勢5.1 插入效率5.2 安全…

SQL進階之旅 Day 19:統計信息與優化器提示

【SQL進階之旅 Day 19】統計信息與優化器提示 文章簡述 在數據庫性能調優中&#xff0c;統計信息和優化器提示是兩個至關重要的工具。統計信息幫助數據庫優化器評估查詢成本并選擇最佳執行計劃&#xff0c;而優化器提示則允許開發人員對優化器的行為進行微調。本文深入探討了…

安寶特方案丨船舶智造AR+AI+作業標準化管理系統解決方案(維保)

船舶維保管理現狀&#xff1a;設備維保主要由維修人員負責&#xff0c;根據設備運行狀況和維護計劃進行定期保養和故障維修。維修人員憑借經驗判斷設備故障原因&#xff0c;制定維修方案。 一、痛點與需求 1 Arbigtec 人工經驗限制維修效率&#xff1a; 復雜設備故障的診斷和…

MFC內存泄露

1、泄露代碼示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 獲取 Ribbon Bar 指針// 創建自定義按鈕CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…

基于區塊鏈的供應鏈溯源系統:構建與實踐

前言 在當今全球化的經濟環境中&#xff0c;供應鏈的復雜性不斷增加&#xff0c;商品從原材料采購到最終交付給消費者的過程涉及多個環節和眾多參與者。如何確保供應鏈的透明度、可追溯性和安全性&#xff0c;成為企業和消費者關注的焦點。區塊鏈技術以其去中心化、不可篡改和透…

Web攻防-SQL注入數據格式參數類型JSONXML編碼加密符號閉合

知識點&#xff1a; 1、Web攻防-SQL注入-參數類型&參數格式 2、Web攻防-SQL注入-XML&JSON&BASE64等 3、Web攻防-SQL注入-數字字符搜索等符號繞過 案例說明&#xff1a; 在應用中&#xff0c;存在參數值為數字&#xff0c;字符時&#xff0c;符號的介入&#xff0c…