国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

算法競賽備賽之經(jīng)典數(shù)據(jù)結(jié)構(gòu)訓(xùn)練提升,暑期集訓(xùn)營培訓(xùn)

這篇具有很好參考價(jià)值的文章主要介紹了算法競賽備賽之經(jīng)典數(shù)據(jù)結(jié)構(gòu)訓(xùn)練提升,暑期集訓(xùn)營培訓(xùn)。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

算法競賽備賽之經(jīng)典數(shù)據(jù)結(jié)構(gòu)訓(xùn)練提升,暑期集訓(xùn)營培訓(xùn),數(shù)據(jù)結(jié)構(gòu)和算法,2023暑期算法集訓(xùn),算法,數(shù)據(jù)結(jié)構(gòu),c++,散列表,哈希算法,鏈表,并查集

1.鏈表與鄰接表:樹與圖的存儲(chǔ)

我們將結(jié)構(gòu)體和指針結(jié)合來實(shí)現(xiàn)鏈表

struct Node
{
 ? ?int val;
 ? ?Node * next;
};
?
new Node;//這樣創(chuàng)建結(jié)點(diǎn)是相當(dāng)慢的

我們算法主要是用數(shù)組來模擬鏈表,這樣效率會(huì)高一些。

數(shù)組模擬單鏈表

鄰接表:存儲(chǔ)圖和樹

實(shí)現(xiàn)一個(gè)單鏈表,鏈表初始為空,支持三種操作:

  1. 向鏈表頭插入一個(gè)數(shù)

  2. 刪除第k個(gè)插入的數(shù)后面的數(shù)

  3. 在第k個(gè)前面插入一個(gè)數(shù)

#include<iostream>
using namespace std;
?
const int N = 100010;
?
//head為頭結(jié)點(diǎn)的下標(biāo)
//e[i]表示節(jié)點(diǎn)i的值
//ne[i]表示節(jié)點(diǎn)i的節(jié)點(diǎn)next指針
//idx存儲(chǔ)當(dāng)前已經(jīng)使用到的點(diǎn)的位置
?
int head, idx, e[N], ne[N];
?
void init()
{
 ? ?head = -1;
 ? ?idx = 0;
}
?
//將x插入到頭結(jié)點(diǎn)
void add_to_head(int x)
{
 ? ?e[idx] = x;
 ? ?ne[idx] = head;
 ? ?head = idx;
 ? ?idx++;
}
?
//將x插入到k的節(jié)點(diǎn)位置
void add(int k, int x)
{
 ? ?e[idx] = x;
 ? ?ne[idx] = ne[k];
 ? ?ne[k] = idx;
 ? ?idx++;
}
?
//將k后面的點(diǎn)去掉
void remove(int k)
{
 ? ?ne[k] = ne[ne[k]];
}
?
int main()
{
 ? ?int m;
 ? ?cin >> m;
 ? ?
 ? ?init();
 ? ?
 ? ?while(m--)
 ?  {
 ? ? ? ?int k, x;
 ? ? ? ?char op;
 ? ? ? ?
 ? ? ? ?cin >> op;
 ? ? ? ?if(op == 'H')
 ? ? ?  {
 ? ? ? ? ? ?cin >> x;
 ? ? ? ? ? ?add_to_head(x);
 ? ? ?  }
 ? ? ? ?else if(op == 'D')
 ? ? ?  {
 ? ? ? ? ? ?cin >> k;
 ? ? ? ? ? ?if(k == 0) head = ne[head];
 ? ? ? ? ? ?remove(k-1);
 ? ? ?  }
 ? ? ? ?else
 ? ? ?  {
 ? ? ? ? ? ?cin >> k >> x;
 ? ? ? ? ? ?add(k-1, x);
 ? ? ?  }
 ?  }
 ? ?
 ? ?for(int i = head;i != -1;i = ne[i])
 ?  {
 ? ? ? ?cout << e[i] << ' ';
 ?  }
 ? ?return 0;
}

數(shù)組模擬雙鏈表的模板

#include<iostream>
using namespace std;
?
const int N = 100010;
?
int m;
int e[N], l[N], r[N], idx;
?
void init()
{
 ? ?//0表示左端點(diǎn),1表示右端點(diǎn)
 ? ?r[0] = 1, l[1] = 0;
 ? ?idx = 2;
}
?
//在下標(biāo)的k的右邊插入x
void add(int k, int x)
{
 ? ?e[idx] = x;
 ?  r[idx] = r[k];
 ? ?l[idx] = k;
 ? ?l[r[k]] = idx;
 ? ?r[k] = idx;
}
?
//刪除第k個(gè)點(diǎn)
void remove(int k)
{
 ? ?r[l[k]] = r[k];
 ? ?l[r[k]] = l[k];
}

2.棧與隊(duì)列:單調(diào)隊(duì)列、單調(diào)棧

棧是先進(jìn)后出,隊(duì)列是先進(jìn)先出。

數(shù)組實(shí)現(xiàn)棧

#include<iostream>
using namespace std;
?
const int N = 100010;
?
int stk[N], tt;
?
//插入stk[++tt] = x;
?
//彈出tt--;
?
//判斷棧是否為空 if(tt>0) 不為空,否則為空
?
//棧頂 stk[tt];

數(shù)組實(shí)現(xiàn)隊(duì)列

#include<iostream>
using namespace std;
?
//在隊(duì)尾插入元素,在隊(duì)頭彈出元素
int q[N], hh, tt = -1;
?
//判斷隊(duì)列是否為空
if(hh <= tt) not empty;
else empty;
?
//取出隊(duì)頭、隊(duì)尾元素
q[hh];
q[tt];

單調(diào)棧例題

給定一個(gè)長度為 N 的整數(shù)數(shù)列,輸出每個(gè)數(shù)左邊第一個(gè)比它小的數(shù),如果不存在則輸出 -1

int tt;
for(int i = 1;i <= n; i++)
{
 ? ?while(tt && check(q[tt], i)) t--;
 ? ?stk[++tt] = i;
}

題目代碼

#include<iostream>
using namespace std;
?
const int N = 1e5 + 10;
?
int n;
int q[N], tt;
?
int main()
{
 ? ?scanf("%d", &n);
 ? ?for(int i = 0;i < n; i++)
 ?  {
 ? ? ? ?int x;
 ? ? ? ?scanf("%d",&x);
 ? ? ? ?while(tt && stk[tt] >= x) tt--;
 ? ? ? ?if(tt) printf("%d ",stk[tt]);
 ? ? ? ?else printf("-1 ");
 ? ? ? ?
 ? ? ? ?stk[++tt] = x;
 ?  }
 ? ?return 0;
}

只有出棧和入棧兩次操作,所以它的時(shí)間復(fù)雜度為O(n)

單調(diào)隊(duì)列例題

移動(dòng)窗口的例題,k為窗口大小且k=3,打印出三個(gè)數(shù)中最小數(shù),如果窗口下數(shù)不足,則輸出-1

1 3 -1 -3 5 3 6 7

由上面的例子我們可以知道在3 -1 -3這個(gè)序列中3絕對不可能為最小值,-3的生命周期要比3長。我們要優(yōu)化該形式,可以用單調(diào)隊(duì)列的形式,將不滿足的點(diǎn)刪掉。

我們的隊(duì)列里存的不是值而是下標(biāo)。

int hh = 0, tt = 1;
for(int i = 0;i < n; i++)
{
 ? ?if(hh <= tt && check_out(q[hh])) hh++;
 ? ?while(hh <= tt && check(q[tt],i)) tt--;
 ? ?q[++tt] = i;
}

本題代碼

#include<iostream>
using namespace std;
?
const int N = 1e6 + 10;
?
int n,k;
int a[N], q[N];
?
int main()
{
 ? ?scanf("%d%d", &n, &k);
 ? ?
 ? ?for(int i = 0;i < n; i++)
 ?  {
 ? ? ? ?scanf("%d", &a[i]);
 ?  }
 ? ?
 ? ?int hh = 0, tt = -1;
 ? ?for(int i = 0;i < n; i++)
 ?  {
 ? ? ? ?//判斷隊(duì)頭是否已經(jīng)超出滑出窗口
 ? ? ? ?if(hh <= tt && i - k + 1 > q[hh]) hh++;
 ? ? ? ?while(hh <= tt && a[q[tt]] >= a[i]) tt--;
 ? ? ? ?q[++tt] = i;
 ? ? ? ?if(i >= k - 1)
 ? ? ? ? ? ?printf("%d ", a[q[hh]]);
 ?  }
 ? ?printf("");
 ? ?
 ? ?return 0;
}

3.kmp算法

KMP算法是一種字符串匹配算法,用于在一個(gè)字符串中查找另一個(gè)字符串出現(xiàn)的位置。它的全名是Knuth-Morris-Pratt算法,是由Donald Knuth、James H. Morris和Victor S. Pratt三人共同發(fā)明的。

S[N],p[M]我們?nèi)绻帽┝λ惴ǎ闼刈龇ǎ﹣碜龅脑?,代碼如下:

for(int i = 1;i <= n; i++)
{
 ? ?bool flag = true;
 ? ?for(int j = 1;j <= m; j++)
 ?  {
 ? ? ? ?if(s[i] != p[j])
 ? ? ?  {
 ? ? ? ? ? ?flag = false;
 ? ? ? ? ? ?break;
 ? ? ?  }
 ?  }
}

KMP算法的思想是在匹配過程中,盡量利用已經(jīng)匹配過的信息來快速跳過不匹配的位置,從而達(dá)到減少匹配次數(shù)和提高匹配效率的目的。具體來說,它通過預(yù)處理出一個(gè)next數(shù)組,來記錄匹配模式串中每個(gè)位置上最長的相同前綴和后綴的長度。在匹配過程中,如果發(fā)現(xiàn)當(dāng)前字符不匹配,就可以利用next數(shù)組中記錄的信息,快速地將模式串向右移動(dòng)一定的距離,而無需重新從頭開始匹配。

KMP算法的時(shí)間復(fù)雜度為O(m+n),其中m和n分別為匹配串和模式串的長度。相比于暴力匹配算法,KMP算法可以在很大程度上減少匹配的次數(shù),從而提高匹配的效率。但是,KMP算法的實(shí)現(xiàn)比較復(fù)雜,需要對next數(shù)組進(jìn)行正確的計(jì)算和處理,因此在實(shí)際應(yīng)用中需要仔細(xì)考慮其實(shí)現(xiàn)方式和適用場景。

next[i] = j, p[1, j] = p[i - j + 1, i]

acwing的KMP算法例題

給定一個(gè)模式串S,以及一個(gè)模板串P,所有字符串中只包含大小寫英文字母以及阿拉伯?dāng)?shù)字。模板串P在模式串S中多次作為子串出現(xiàn)。求出模板串P在模式串S中所有出現(xiàn)的位置的起始下標(biāo)。

輸入樣例:3 aba 5 ababa 輸出:0 2

代碼:

#include<iostream>
using namespace std;
?
const int N = 1e4 + 10, M = 1e5 + 10;
?
int n, m;
char p[N], s[M];
int ne[N];
?
int main()
{
 ? ?cin >> n >> p + 1 >> m >> s + 1;
 ? ?
 ? ?//求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;
 ?  }
 ? ?
 ? ?//kmp的匹配過程
 ? ?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)
 ? ? ?  {
 ? ? ? ? ? ?//匹配成功
 ? ? ? ? ? ?printf("%d ",i - n);
 ? ? ? ? ? ?j = ne[j];
 ? ? ?  }
 ?  }
 ? ?return 0;
}

4.Trie樹

Trie(又稱前綴樹或字典樹)是一種基于樹結(jié)構(gòu)的數(shù)據(jù)結(jié)構(gòu),用于快速地檢索和插入字符串。Trie的每個(gè)節(jié)點(diǎn)代表一個(gè)字符串的前綴,從根節(jié)點(diǎn)到葉子節(jié)點(diǎn)的路徑上表示一個(gè)完整的字符串。

Trie的特點(diǎn)是它的每個(gè)節(jié)點(diǎn)都有多個(gè)子節(jié)點(diǎn),每個(gè)子節(jié)點(diǎn)代表一個(gè)字符。根節(jié)點(diǎn)沒有父節(jié)點(diǎn),每個(gè)非葉子節(jié)點(diǎn)的子節(jié)點(diǎn)數(shù)等于它的編號(hào)(從0開始)減去1。

在Trie中,插入一個(gè)字符串的操作是從根節(jié)點(diǎn)開始,按照字符串的字符順序依次遍歷每個(gè)字符,如果當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)中沒有對應(yīng)字符,就新建一個(gè)子節(jié)點(diǎn),并將當(dāng)前節(jié)點(diǎn)移動(dòng)到該子節(jié)點(diǎn)。如果已經(jīng)遍歷到字符串的末尾,則說明該字符串已經(jīng)成功插入到Trie中。

Trie的另一個(gè)常見操作是查找一個(gè)字符串是否存在于Trie中。從根節(jié)點(diǎn)開始,按照字符串的字符順序依次遍歷每個(gè)字符,如果當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)中沒有對應(yīng)字符,則說明該字符串不存在于Trie中。如果已經(jīng)遍歷到字符串的末尾,且當(dāng)前節(jié)點(diǎn)是一個(gè)葉子節(jié)點(diǎn),則說明該字符串存在于Trie中。

Trie的主要優(yōu)勢是它可以快速地檢索和插入字符串,時(shí)間復(fù)雜度為O(m),其中m為字符串的長度。但是,由于Trie的每個(gè)節(jié)點(diǎn)都需要存儲(chǔ)多個(gè)子節(jié)點(diǎn),因此它的空間復(fù)雜度比較高,適用于數(shù)據(jù)規(guī)模較小的情況。在大數(shù)據(jù)處理和文本處理等領(lǐng)域,Trie通常被用來實(shí)現(xiàn)詞典和關(guān)鍵字過濾等功能。

trie字符串統(tǒng)計(jì)

維護(hù)一個(gè)字符串集合,支持兩種操作:

  1. ‘lx’向集合中插入一個(gè)字符串x

  2. ‘Qx’詢問一個(gè)字符串在集合中出現(xiàn)了多少次

一共有N次操作,輸入的字符串總長度不超過105,字符串僅包含小寫英文字母。

#include<iostream>
using namespace std;
?
const int N = 1e5 + 10;
?
int son[N][26], cnt[N], idx;//下標(biāo)是0的點(diǎn),既是根節(jié)點(diǎn),有是空節(jié)點(diǎn)
int str[N];
?
void insert(char str[])
{
 ? ?int p = 0;
 ? ?for(int i = 0;str[i]; i++)
 ?  {
 ? ? ? ?int u = str[i] - 'a';
 ? ? ? ?if(!son[p][u]) son[p][u] = ++idx;
 ? ? ? ?p = son[p][u];
 ?  }
 ? ?
 ? ?cnt[p]++;
}
?
int query(char str[])
{
 ? ?int p = 0;
 ? ?for(int i = 0;str[i]; i++)
 ?  {
 ? ? ? ?int u = str[i] - 'a';
 ? ? ? ?if(!son[p][u]) return 0;
 ? ? ? ?p = son[p][u];
 ?  }
 ? ?
 ? ?return cnt[p];
}
?
int main()
{
 ? ?int n;
 ? ?scanf("%d", &n);
 ? ?while(n--)
 ?  {
 ? ? ? ?char op[2];
 ? ? ? ?scanf("%s%s", op, str);
 ? ? ? ?if(op == 'I') insert(str);
 ? ? ? ?else printf("%d\n", query(str));
 ?  }
 ? ?return 0;
}

最大異或?qū)?/strong>

5.并查集

并查集是一種樹型的數(shù)據(jù)結(jié)構(gòu),用于處理一些不相交集合的合并及查詢問題。

  1. 將兩個(gè)集合合并

  2. 詢問兩個(gè)元素是否在一個(gè)集合當(dāng)中。

基本原理:每隔幾何用一棵樹來表示,樹根的編號(hào)就是一整個(gè)集合的編號(hào)。每個(gè)節(jié)點(diǎn)存儲(chǔ)它的父節(jié)點(diǎn),p[x]表示x的父節(jié)點(diǎn)。

問題1:如何判斷樹根:if(p[x] == x);

問題2:如何求x的集合編號(hào):while(p[x] != x) x = p[x];

問題3:如何合并兩個(gè)集合:px是x的集合編號(hào),py是y的集合編號(hào)。p[x] = y

基本上來說是O(1)的時(shí)間復(fù)雜度

合并集合

一共有n個(gè)數(shù),編號(hào)是1~n,最開始每個(gè)數(shù)各自在一個(gè)集合中。

現(xiàn)在要進(jìn)行m個(gè)操作,操作一共有兩種

  1. 將編號(hào)為a,b的兩個(gè)數(shù)所在集合進(jìn)行合并,如果兩個(gè)數(shù)已經(jīng)在集合中,即忽略這個(gè)操作

  2. 詢問編號(hào)為a,b的兩個(gè)數(shù)是否在同一個(gè)集合中

#include<iostream>
using namespace std;
?
const int N = 1e5 + 10;
?
int n, m;
int p[N];
?
int find(int x)//返回x的祖宗結(jié)點(diǎn)+路徑壓縮
{
 ? ?if(p[x] != x) p[x] = find(p[x]);
 ? ?return p[x];
}
?
void merge(int a, int b)
{
 ? ?p[find(a)] = find(b);
}
?
int main()
{
 ? ?scanf("%d%d", &n, &m);
 ? ?
 ? ?for(int i = 1;i <= n; i++)
 ?      p[i] = i;
 ? ?
 ? ?while(m--)
 ?  {
 ?      char op[2];
 ? ? ? ?int a, b;
 ? ? ? ?scanf("%s%d%d", op, &a, &b);
 ? ? ? ?
 ? ? ? ?if(op[0] == 'M')
 ? ? ? ? ? ?merge(a, b);
 ? ? ? ?else
 ? ? ?  {
 ? ? ? ? ? ?if(find(a) == find(b))
 ? ? ? ? ? ? ? ?printf("Yes\n");
 ? ? ? ? ? ?else
 ? ? ? ? ? ? ? ?printf("No\n");
 ? ? ?  }
 ?  }
 ? ?
 ? ?return 0;
}

近乎O(1)的時(shí)間

連通塊中點(diǎn)的數(shù)量

給定一個(gè)包含n個(gè)點(diǎn)(編號(hào)為1~n)的無向圖,初始時(shí)圖中沒有邊。

現(xiàn)在要進(jìn)行m個(gè)操作,操作一共有三個(gè):

  1. “Cab”,在點(diǎn)a和點(diǎn)b之間連一條邊,a和b可能相等

  2. “Q1ab”,詢問點(diǎn)a和點(diǎn)b是否在同一連通塊內(nèi),a和b可能相等

  3. “Q2ab”,詢問點(diǎn)a所在的聯(lián)通快中點(diǎn)的個(gè)數(shù)。

#include<iostream>
using namespace std;
?
const int N = 1e5 + 10;
?
int n, m;
int p[N], size[N];
?
int find(int x)
{
 ? ?if(p[x] != x) p[x] = find(p[x]);
 ? ?return p[x];
}
?
void merge(int a, int b)
{
 ? ?p[find(a)] = find(b);
}
?
int main()
{
 ? ?scanf("%d%d", &n, &m);
 ? ?
 ? ?for(int i = 1;i <= n; i++)
 ?  {
 ? ? ? ?p[i] = i;
 ? ? ? ?size[i] = 1;
 ?  }
 ? ?
 ? ?while(m--)
 ?  {
 ? ? ? ?char op[5];
 ? ? ? ?int a, b;
 ? ? ? ?
 ? ? ? ?scanf("%s", op);
 ? ? ? ?
 ? ? ? ?if(op[0] == 'C')
 ? ? ?  {
 ? ? ? ? ? ?scanf("%d%d", &a, &b);
 ? ? ? ? ? ?if(find(a) == find(b)) continue;
 ? ? ? ? ? ?size[find(b)] += size[find(a)];
 ? ? ? ? ? ?merge(a, b);
 ? ? ?  }
 ? ? ? ?else if(op[1] == '1')
 ? ? ?  {
 ? ? ? ? ? ?scanf("%d%d", &a, &b);
 ? ? ? ? ? ?if(find(a) == find(b))
 ? ? ? ? ? ? ? ?printf("Yes\n");
 ? ? ? ? ? ?else
 ? ? ? ? ? ? ? ?printf("No\n");
 ? ? ?  }
 ? ? ? ?else
 ? ? ?  {
 ? ? ? ? ? ?scanf("%d", &a);
 ? ? ? ? ? ?printf("%d\n", size[find(a)]);
 ? ? ?  }
 ? ? ? ?
 ?  }
 ? ?return 0;
}

食物鏈

動(dòng)物王國中有三類動(dòng)物A,B,C,這三類動(dòng)物的食物鏈構(gòu)成了有趣的環(huán)形。

A吃B, B吃C,C吃A。

現(xiàn)有N個(gè)動(dòng)物,以1-N編號(hào)。

每個(gè)動(dòng)物都是A,B,C中的一種,但是我們并不知道它到底是哪一種。

有人用兩種說法對這N個(gè)動(dòng)物所構(gòu)成的食物鏈關(guān)系進(jìn)行描述:

第一種說法是”1 X Y”,表示X和Y是同類。

第二種說法是”2 X Y”,表示X吃Y。

此人對N個(gè)動(dòng)物,用上述兩種說法,一句接一句地說出K句話,這K句話有的是真的,有的是假的。

當(dāng)一句話滿足下列三條之一時(shí),這句話就是假話,否則就是真話。

1) 當(dāng)前的話與前面的某些真的話沖突,就是假話; 2) 當(dāng)前的話中X或Y比N大,就是假話; 3) 當(dāng)前的話表示X吃X,就是假話。

你的任務(wù)是根據(jù)給定的N和K句話,輸出假話的總數(shù)。

#include<iostream>
using namespace std;
?
int main()
{
 ? ?return 0;
}

6.堆

如何手寫一個(gè)堆?

堆是維護(hù)數(shù)與集合。

堆是一種數(shù)據(jù)結(jié)構(gòu),它滿足以下兩個(gè)條件:

  1. 完全二叉樹:堆的總是一棵完全二叉樹,即除了最后一層外,其他層都是滿的,并且最后一層的節(jié)點(diǎn)都集中在左側(cè)。

  2. 堆性質(zhì):對于每個(gè)節(jié)點(diǎn)X,其父節(jié)點(diǎn)的值小于等于(或大于等于,稱為最小堆)其子節(jié)點(diǎn)的值。

堆通常用于實(shí)現(xiàn)優(yōu)先隊(duì)列,其中每個(gè)節(jié)點(diǎn)代表一個(gè)事件或任務(wù),節(jié)點(diǎn)的值表示任務(wù)的優(yōu)先級(jí)。通過將任務(wù)按照優(yōu)先級(jí)從上到下放置在堆中,可以保證優(yōu)先級(jí)最高的任務(wù)總是最先被執(zhí)行。

在實(shí)現(xiàn)上,堆可以使用數(shù)組來表示。對于一個(gè)節(jié)點(diǎn)X,其父節(jié)點(diǎn)和子節(jié)點(diǎn)的位置可以通過簡單的數(shù)學(xué)計(jì)算來確定。例如,對于一個(gè)最小堆,節(jié)點(diǎn)X的父節(jié)點(diǎn)和左子節(jié)點(diǎn)的位置可以通過以下公式計(jì)算:

  • 父節(jié)點(diǎn)位置:parent(X) = (X-1)/2

  • 左子節(jié)點(diǎn)位置:left_child(X) = 2*X + 1

堆也可以用來實(shí)現(xiàn)優(yōu)先級(jí)調(diào)度、任務(wù)調(diào)度等應(yīng)用。

  1. 插入一個(gè)數(shù) heap[++size] = x; up(size);

  2. 求集合當(dāng)中的最小值 heap[1];

  3. 刪除最小值 用最后一個(gè)元素覆蓋根節(jié)點(diǎn) heap[1] = heap[size];size--;down(1);

  4. 刪除任意元素 heap[k] = heap[size];size--;

  5. 修改任意元素 heap[k] = x; down(k); up(k);

838.堆排序

輸入一個(gè)長度為n的整數(shù)數(shù)列,從小到大輸出前m小的數(shù)。

輸入格式:第一行包含整數(shù)n和m,第二行包含n個(gè)整數(shù),表示整數(shù)數(shù)列。

輸出格式:共一行,包含m個(gè)整數(shù),表示整數(shù)數(shù)列中前m小的數(shù)。

5 3 \n 4 5 1 3 2

1 2 3

代碼

#include<iostream>
#include<algorithm>
?
using namespace std;
?
const int N = 1e5 + 10;
?
int n, m;
int h[N], size;
?
void down(int u)
{
 ? ?int t = u;
 ? ?if(u * 2 <= size && h[u * 2] < h[t]) t = u * 2;
 ? ?if(u * 2 + 1 <= size && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
 ? ?if(u != t)
 ?  {
 ? ? ? ?swap(h[u], h[t]);
 ? ? ? ?down(t);
 ?  }
}
?
int main()
{
 ? ?scanf("%d%d", &n, &m);
 ? ?for(int i = 1;i <= n; i++)
 ? ? ? ?scanf("%d", &h[i]);
 ? ?size = n;
 ? ?
 ? ?for(int i = n / 2; i; i--)
 ?      down(i);
 ? ?
 ? ?while(m--)
 ?  {
 ? ? ? ?printf("%d ", h[1]);
 ? ? ? ?h[1] = h[size];
 ? ? ? ?size--;
 ? ? ? ?down(1);
 ?  }
 ? ?
 ? ?return 0;
}

839.模擬堆

維護(hù)一個(gè)集合,初始時(shí)集合為空,支持如下幾種操作:

  1. "lx",插入一個(gè)數(shù)x;

  2. “PM”,輸出當(dāng)前集合中的最小值;

  3. “DM”,刪除當(dāng)前集合的最小值(當(dāng)最小值不唯一時(shí),刪除最早插入的最小值);

  4. “Dk”,刪除第k個(gè)插入的數(shù);

  5. “Ckx”,修改第k個(gè)插入的數(shù),將其變?yōu)閤;

現(xiàn)在要進(jìn)行N次操作。對于所有第2個(gè)操作,輸出當(dāng)前集合的是小值。

#include<iostream>
#include<algorithm>
#include<string.h>
?
using namespace std;
?
const int N = 1e5 + 10;
?
int h[N], ph[N], hp[N], size;
?
void heap_swap(int a, int b)
{
 ? ?swap(ph[hp[a]], ph[hp[b]]);
 ? ?swap(hp[a], hp[b]);
 ? ?swap(h[a], h[b]);
}
?
void down(int u)
{
 ? ?int t = u;
 ? ?if(u * 2 <= size && h[u * 2] < h[t]) t = u * 2;
 ? ?if(u * 2 + 1 <= size && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
 ? ?if(u != t)
 ?  {
 ? ? ? ?heap_swap(u, t);
 ? ? ? ?down(t);
 ?  }
}
?
void up(int u)
{
 ? ?while(u / 2 && h[u / 2] > h[u])
 ?  {
 ? ? ? ?heap_swap(u / 2, u);
 ? ? ? ?u /= 2;
 ?  }
}
?
int main()
{
 ? ?int n, m = 0;
 ? ?scanf("%d", &n);
 ? ?
 ? ?while(n--)
 ?  {
 ? ? ? ?char op[10];
 ? ? ? ?int k, x;
 ? ? ? ?
 ? ? ? ?scanf("%s", op);
 ? ? ? ?if(!strcmp(op, "I"))
 ? ? ?  {
 ? ? ? ? ? ?scanf("%d", &x);
 ? ? ? ? ? ?size++;
 ? ? ? ? ? ?m++;
 ? ? ? ? ? ?ph[m] = size, hp[size] = m;
 ? ? ? ? ? ?h[size] = x;
 ? ? ? ? ? ?up(size);
 ? ? ?  }
 ? ? ? ?else if(!strcmp(op, "PM")) printf("%d\n", h[1]);
 ? ? ? ?else if(!strcmp(op, "DM"))
 ? ? ?  {
 ? ? ? ? ? ?heap_swap(1, size);
 ? ? ? ? ? ?size--;
 ? ? ? ? ? ?down(1);
 ? ? ?  }
 ? ? ? ?else if(!strcmp(op, "D"))
 ? ? ?  {
 ? ? ? ? ? ?scanf("%d", &k);
 ? ? ? ? ? ?k = ph[k];
 ? ? ? ? ? ?heap_swap(k, size);
 ? ? ? ? ? ?size--;
 ? ? ? ? ? ?down(k), up(k);
 ? ? ?  }
 ? ? ? ?else
 ? ? ?  {
 ? ? ? ? ? ?scanf("%d%d", &k, &x);
 ? ? ? ? ? ?k = ph[k];
 ? ? ? ? ? ?h[k] = x;
 ? ? ? ? ? ?down(k), up(k);
 ? ? ?  }
 ?  }
 ? ?
 ? ?return 0;
}

7.Hash表

哈希表是一種使用哈希函數(shù)組織數(shù)據(jù),以支持快速插入和搜索的數(shù)據(jù)結(jié)構(gòu)。

哈希表可以用來實(shí)現(xiàn)動(dòng)態(tài)集合。它支持以下操作:

  • 插入:將一個(gè)元素插入到哈希表中。

  • 刪除:將一個(gè)元素從哈希表中刪除。

  • 搜索:在哈希表中查找一個(gè)元素。

哈希表的實(shí)現(xiàn)基于哈希函數(shù),它將鍵映射到存儲(chǔ)桶(bucket)中。每個(gè)存儲(chǔ)桶是一個(gè)鏈表,鏈表中的每個(gè)節(jié)點(diǎn)都包含一個(gè)鍵值對。當(dāng)插入一個(gè)元素時(shí),哈希函數(shù)將鍵映射到一個(gè)存儲(chǔ)桶,然后將元素添加到該存儲(chǔ)桶的鏈表中。當(dāng)搜索一個(gè)元素時(shí),哈希函數(shù)將鍵映射到相應(yīng)的存儲(chǔ)桶,然后在該存儲(chǔ)桶的鏈表中查找元素。

哈希表有多種實(shí)現(xiàn)方式,其中最常用的是開放地址法和相聯(lián)數(shù)組法。開放地址法在哈希表中使用一個(gè)數(shù)組來存儲(chǔ)存儲(chǔ)桶,當(dāng)發(fā)生哈希沖突時(shí),它使用線性探測、二次探測、雙重散列等方法來找到空槽位。相聯(lián)數(shù)組法在哈希表中直接使用一個(gè)數(shù)組來存儲(chǔ)鍵值對,當(dāng)發(fā)生哈希沖突時(shí),它將新元素添加到數(shù)組的末尾。

哈希表在計(jì)算機(jī)科學(xué)中廣泛應(yīng)用,例如在數(shù)據(jù)庫、操作系統(tǒng)、網(wǎng)絡(luò)通信等領(lǐng)域。它能夠提供常數(shù)級(jí)別的查找效率,比其他數(shù)據(jù)結(jié)構(gòu)更高效。

7.1哈希表的存儲(chǔ)結(jié)構(gòu)

1.開放尋址法 2.拉鏈法

840.模擬散列表

維護(hù)一個(gè)集合,支持如下幾種操作:

  1. “l(fā)x”,插入一個(gè)數(shù)

  2. “Qx”,詢問數(shù)x是否在集合中出現(xiàn)過

現(xiàn)在要進(jìn)行N次操作,對于每個(gè)詢問操作輸出對應(yīng)的結(jié)果

一般情況下,對哈希函數(shù)進(jìn)行取模,但是由于取模的原因,可能會(huì)有沖突,若干不同的數(shù)可能會(huì)映射在同一個(gè)位置。

開放尋址法

#include<iostream>
#include<cstring>
?
using namespace std;
?
cosnt int N = 200003, null = 0x3f3f3f3f;
?
int h[N];
?
int find(int n)
{
 ? ?int t = (x % N + N) % N;
 ? ?
 ? ?while(h[t] != null && h[t] != x)
 ?  {
 ? ? ? ?t++;
 ? ? ? ?if(t == N)
 ? ? ? ? ? ?t = 0;
 ?  }
 ? ?
 ? ?return t;
}
?
int main()
{
 ? ?int n;
 ? ?scanf("%d", &n);
 ? ?merset(h, 0x3f, sizeof(h));
 ? ?
 ? ?while(n--)
 ?  {
 ? ? ? ?char op[2];
 ? ? ? ?int x;
 ? ? ? ?scanf("%s%d", op, &x);
 ? ? ? ?
 ? ? ? ?int k = find(x);
 ? ? ? ?if (op == 'I')
 ? ? ?  {
 ? ? ? ? ? ?h[k] = x;
 ? ? ?  }
 ? ? ? ?else
 ? ? ?  {
 ? ? ? ? ? ?if (h[k] != null) 
 ? ? ? ? ? ? ? ?puts("Yes");
 ? ? ? ? ? ?else
 ? ? ? ? ? ? ? ?puts("No");
 ? ? ?  }
 ?  }
 ? ?return 0;
}

拉鏈法

#include<iostream>
#include<cstring>
?
using namespace std;
?
const int N = 100003;
?
int h[N], e[N], ne[N], idx;
?
void insert(int x)
{
 ? ?int k = (x % N + N) % N;
 ? ?
 ? ?e[idx] = x;
 ? ?ne[idx] = h[k];
 ? ?h[k] = idx++;
}
?
bool find(int x)
{
 ? ?int k = (x % N + N) % N;
 ? ?for(int i = h[k];i != -1; i = ne[i])
 ?      if(e[i] == x)
 ? ? ? ? ? ?return true;
 ?      else
 ? ? ? ? ? ?return false;
}
?
int main()
{
 ? ?int n;
 ? ?scanf("%d", &n);
 ? ?
 ? ?memset(h, -1, sizeof(h));
 ? ?
 ? ?while(n--)
 ?  {
 ? ? ? ?char op[2];
 ? ? ? ?int x;
 ? ? ? ?scanf("%s%d", op, &x);
 ? ? ? ?
 ? ? ? ?if(op == "I") insert(x);
 ? ? ? ?else
 ? ? ?  {
 ? ? ? ? ? ?if(find(x)) puts("Yes");
 ? ? ? ? ? ?else puts("No");
 ? ? ?  }
 ?  }
 ? ?return 0;
}

7.2.字符串前綴哈希方法

str = "ABCDEFADCYUGHJJDFDGKHJK"

預(yù)處理:特殊h[0] = 0

h[1] = "A"的對應(yīng)的哈希值,后面的一樣 h[2] = "AB" h[3] = "ABC".....

  1. 不能映射為0

  2. Rp足夠好,不產(chǎn)生沖突

841.字符串哈希

給定個(gè)長度為的字符串,再給定m個(gè)詢問,每個(gè)詢問包含四個(gè)整數(shù)l1,r1,l2,r2,請你判斷[l1,r1]和[l2,r2]這兩個(gè)區(qū)間所包含的字符串子串是否完全相同。

字符串中只包含大小寫英文字母和數(shù)字。

#include<iostream>
using namespace std;
?
typedef unsigned long long ULL;
?
const int N = 100010;
?
int n, m;
char str[N];
ULL h[N], p[N];
?
ULL get(int l, int r)
{
 ? ?return h[r] - h[l - 1] * p[r - l + 1];
}
?
int main()
{
 ? ?scanf("%d%d%s", &n, &m, str + 1);
 ? ?
 ? ?p[0] = 1;
 ? ?for(int i = 1;i <= n; i++)
 ?  {
 ? ? ? ?p[i] = p[i-1] * p;
 ? ? ? ?h[i] = h[i-1] * p + str[i];
 ?  }
 ? ?
 ? ?while(m--)
 ?  {
 ? ? ? ?int l1, r1, l2, r2;
 ? ? ? ?scanf("%d%d%d%d",&l1, &r1, &l2, &r2);
 ? ? ? ?
 ? ? ? ?if(get(l1, r1) == get(l2, r2))
 ? ? ? ? ? ?puts("Yes");
 ? ? ? ?else
 ? ? ? ? ? ?puts("No");
 ?  }
 ? ?return 0;
}

8.C++STL使用技巧

vector:變長數(shù)組,倍增的思想

string:字符串,substr(),c_str()

queue:隊(duì)列,push(), front(), pop()

priority_queue:優(yōu)先隊(duì)列,push(), top(),pop()

stack:棧,push(), top(), pop()

deque:雙增隊(duì)列

set, map, multiset和multimap:基于平衡二叉樹,動(dòng)態(tài)維護(hù)有序序列

unorder_set、unorder_map、unorder_multiset、unorder_multimap:基于哈希表

bitset:壓位

list

#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<cstdio>
?
using namespace std;
?
int main()
{
 ? ?vector<int> a(10, 3);
 ? ?//vector<int> a[10];
 ? ?a.size();//返回元素個(gè)數(shù)
 ? ?a.empty();//返回是否為空
 ? ?a.clear();//清空
 ? ?a.front();//返回第一個(gè)數(shù)
 ? ?a.back();//返回最后一個(gè)數(shù)
 ? ?a.push_back();//尾插
 ? ?a.pop_back();//尾部釋放
 ? ?a.begin()/a.end();//vector的迭代器
 ? ?
 ? ?for(int i = 0;i < 10; i++)
 ? ? ? ?a.push_back();
 ? ?
 ? ?for(int i = 0;i < a.size(); i++)
 ? ? ? ?cout << a[i] << ' ';
 ? ?cout << endl;
 ? ?
 ? ?for(vector<int>::iterator i = a.begin();i != a.end(); i++)
 ? ? ? ?cout << a[i] << ' ';
 ? ?cout << endl;
 ? ?
 ?  //支持比較運(yùn)算
 ? ?vector<int> a(4, 3), b(3, 4);
 ? ?if(a > b) cout << "a > b" << endl;
 ? ?
 ? ?return 0;
}

系統(tǒng)內(nèi)某一程序分配空間時(shí),所需時(shí)間,與空間大小無關(guān),與中間次數(shù)有關(guān)

pair<int, int>:存儲(chǔ)一個(gè)二元組

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
?
using namespace std;
?
int main()
{
 ? ?pair<int, string>p;
 ? ?
 ? ?p.first;
 ? ?p.second;
 ? ?//支持比較運(yùn)算
 ? ?//以first為第一關(guān)鍵詞,以second為第二關(guān)鍵詞
 ? ?
 ? ?p = make_pair(10, "yxc");
 ? ?p = {20, "abc"};
 ? ?
 ? ?pair<int, pair<int>>w;
 ? ?return 0;
}

string

#include<iostream>
#include<cstring>
#include<algorithm>
?
using namespace std;
?
int main()
{
 ? ?string a = "yxc";
 ? ?
 ? ?a += "def";
 ? ?a += "c";
 ? ?
 ? ?cout << a << endl;
 ? ?cout << a.substr(2, 3) << endl;
 ? ?
 ? ?return 0;
}

queue隊(duì)列

#include<iostream>
#include<queue>
#include<algorithm>
#include<vector>
?
using namespace std;
?
int main()
{
 ? ?queue<int> q;
 ? ?
 ? ?q = queue<int>;
 ? ?
 ? ?//優(yōu)先隊(duì)列
 ? ?priority_queue<int> heap;
 ? ?heap.clear();
 ? ?
 ? ?priority_queue<int, vector<int>, greater<int>> heap;//定義一個(gè)小根堆
 ? ?return 0;
}

stack棧

deque雙端隊(duì)列

size() empty() clear() front() back() push_front() pop_front() push_back pop_back() begin() end()

缺點(diǎn)就是deque比較慢

set

#include<iostream>
#include<vector>
#include<set>
#include<algorithm>
?
using namespace std;
?
int main()
{
 ? ?set<int> S;
 ? ?multiset<int> S1;//可以有重復(fù)元素,set不允許
 ? ?
 ? ?S.insert(1);//插入一個(gè)數(shù)
 ? ?S.find();//查找一個(gè)數(shù)
 ? ?S.count();//返回某一個(gè)數(shù)的個(gè)數(shù)
 ? ?S.erase();//1.輸入的是一個(gè)數(shù),就刪除該數(shù)的所有存儲(chǔ) 2.輸入一個(gè)迭代器,就刪除這個(gè)迭代器
 ? ?S.lower_bound(x);//返回大于等于x的最小的數(shù)的迭代器
 ? ?S.upper_bound(x);//返回大于x的最小數(shù)的迭代器
 ? ?
 ? ?return 0;
}

map/multimap

insert()插入的數(shù)是一個(gè)pair erase()輸入的參數(shù)是pair或者是迭代器 find()

[] 時(shí)間復(fù)雜度是O(nlogn) lower_bound() upper_bound()

unordered_set, unordered_map, unordered_multiset, unordered_multimap

哈希表 和上面的類似,增刪查改的時(shí)間復(fù)雜度是O(1)

不支持lower_bound()和upper_bound(),迭代器的++、--

bitset,壓位

bitset<10000>S;~, &, |, ^, >>, <<, ==, !=,

count()返回有多少個(gè)1

any()判斷是否至少有一個(gè)1

none()判斷是否為0

set()把所有位置都換成1

reset()把所有位都變成0

flip()等價(jià)~ flip(k)把第k位反轉(zhuǎn)。

算法競賽備賽之經(jīng)典數(shù)據(jù)結(jié)構(gòu)訓(xùn)練提升,暑期集訓(xùn)營培訓(xùn),數(shù)據(jù)結(jié)構(gòu)和算法,2023暑期算法集訓(xùn),算法,數(shù)據(jù)結(jié)構(gòu),c++,散列表,哈希算法,鏈表,并查集

?文章來源地址http://www.zghlxwxcb.cn/news/detail-600811.html

到了這里,關(guān)于算法競賽備賽之經(jīng)典數(shù)據(jù)結(jié)構(gòu)訓(xùn)練提升,暑期集訓(xùn)營培訓(xùn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 算法競賽:初級(jí)算法(第一章:基礎(chǔ)數(shù)據(jù)結(jié)構(gòu))

    動(dòng)態(tài)鏈表 動(dòng)態(tài)鏈表需要 臨時(shí)分配鏈表節(jié)點(diǎn) ,使用完畢后釋放。 優(yōu)點(diǎn) :能及時(shí)釋放空間,不使用多余內(nèi)存 缺點(diǎn) :需要管理空間,容易出錯(cuò)(競賽一般不用動(dòng)態(tài)鏈表) 靜態(tài)鏈表 靜態(tài)鏈表使用 預(yù)先分配的一段連續(xù)空間 存儲(chǔ)鏈表,這種鏈表在邏輯上是成立的。 有兩種做法:

    2024年01月19日
    瀏覽(32)
  • 數(shù)據(jù)結(jié)構(gòu)(五)數(shù)據(jù)結(jié)構(gòu)與算法中的經(jīng)典題

    本文是在原本數(shù)據(jù)結(jié)構(gòu)與算法闖關(guān)的基礎(chǔ)上總結(jié)得來,加入了自己的理解和部分習(xí)題講解。至此數(shù)據(jù)結(jié)構(gòu)介紹已完結(jié),后續(xù)會(huì)把數(shù)據(jù)結(jié)構(gòu)算法題系列更完。 原活動(dòng)鏈接 邀請碼: JL57F5 根據(jù)要求完成題目 Q1. (單選)以下哪些數(shù)據(jù)結(jié)構(gòu)支持隨機(jī)訪問? A. 數(shù)組 B. 單鏈表 C. 雙向鏈表

    2024年01月20日
    瀏覽(26)
  • 【數(shù)據(jù)結(jié)構(gòu)與算法】十大經(jīng)典排序算法-插入排序

    【數(shù)據(jù)結(jié)構(gòu)與算法】十大經(jīng)典排序算法-插入排序

    ?? 個(gè)人博客: www.hellocode.top ?? Java知識(shí)導(dǎo)航: Java-Navigate ?? CSDN: HelloCode. ?? 知乎 :HelloCode ?? 掘金 :HelloCode ?如有問題,歡迎指正,一起學(xué)習(xí)~~ 插入排序(Insertion Sort)是一種簡單直觀的排序算法,其基本思想是將一個(gè)記錄插入到已排好序的有序序列中,直到所有記錄

    2024年02月13日
    瀏覽(25)
  • 【數(shù)據(jù)結(jié)構(gòu)與算法】十大經(jīng)典排序算法-希爾排序

    【數(shù)據(jù)結(jié)構(gòu)與算法】十大經(jīng)典排序算法-希爾排序

    ?? 個(gè)人博客: www.hellocode.top ?? Java知識(shí)導(dǎo)航: Java-Navigate ?? CSDN: HelloCode. ?? 知乎 :HelloCode ?? 掘金 :HelloCode ?如有問題,歡迎指正,一起學(xué)習(xí)~~ 希爾排序是一種插入排序的改進(jìn)版本,旨在解決插入排序在處理大規(guī)模數(shù)據(jù)時(shí)的效率問題。通過將數(shù)組分為多個(gè)子序列并對

    2024年02月12日
    瀏覽(30)
  • 【數(shù)據(jù)結(jié)構(gòu)與算法】十大經(jīng)典排序算法-冒泡排序

    【數(shù)據(jù)結(jié)構(gòu)與算法】十大經(jīng)典排序算法-冒泡排序

    ?? 個(gè)人博客: www.hellocode.top ?? Java知識(shí)導(dǎo)航: Java-Navigate ?? CSDN: HelloCode. ?? 掘金 :HelloCode ?? 知乎 :HelloCode ?如有問題,歡迎指正,一起學(xué)習(xí)~~ 冒泡排序(Bubble Sort)是一種簡單的排序算法,它通過重復(fù)地交換相鄰元素的位置來將最大(或最?。┑脑刂鸩健懊芭荨钡?/p>

    2024年02月14日
    瀏覽(26)
  • 【數(shù)據(jù)結(jié)構(gòu)與算法】之多指針?biāo)惴ń?jīng)典問題

    【數(shù)據(jù)結(jié)構(gòu)與算法】之多指針?biāo)惴ń?jīng)典問題

    本文為 【數(shù)據(jù)結(jié)構(gòu)與算法】多指針?biāo)惴ń?jīng)典問題 相關(guān)介紹,下邊將對 鏈表反轉(zhuǎn) (包含 迭代反轉(zhuǎn)鏈表 、 遞歸反轉(zhuǎn) 、 頭插法反轉(zhuǎn) ), 雙指針-快慢指針 (包含 尋找單向無環(huán)鏈表的中點(diǎn) 、 判斷單向鏈表是否有環(huán)及找環(huán)入口 ), 雙指針-左右指針 (包含 兩數(shù)之和 、 二分查

    2024年02月03日
    瀏覽(19)
  • 【數(shù)據(jù)結(jié)構(gòu)與算法】十大經(jīng)典排序算法-快速排序

    【數(shù)據(jù)結(jié)構(gòu)與算法】十大經(jīng)典排序算法-快速排序

    ?? 個(gè)人博客: www.hellocode.top ?? Java知識(shí)導(dǎo)航: Java-Navigate ?? CSDN: HelloCode. ?? 知乎 :HelloCode ?? 掘金 :HelloCode ?如有問題,歡迎指正,一起學(xué)習(xí)~~ 快速排序(Quick Sort)是一種高效的排序算法,是對冒泡排序的優(yōu)化。它采用分治法(Divide and Conquer)的思想,將待排序序列

    2024年02月13日
    瀏覽(25)
  • 【數(shù)據(jù)結(jié)構(gòu)與算法】:10道鏈表經(jīng)典OJ

    【數(shù)據(jù)結(jié)構(gòu)與算法】:10道鏈表經(jīng)典OJ

    思路1:遍歷原鏈表,將 val 所在的節(jié)點(diǎn)釋放掉。(太麻煩) 思路2:創(chuàng)建新鏈表,再遍歷原鏈表,找到不為 val 的節(jié)點(diǎn)尾插到新鏈表。 思路1代碼實(shí)現(xiàn)如下: 注意: 1.當(dāng)鏈表為空時(shí),直接返回NULL即可。 2.當(dāng)尾插上最后一個(gè)有效節(jié)點(diǎn)時(shí),此時(shí)它的 next 可能還與最后一個(gè)節(jié)點(diǎn)相鏈接,

    2024年04月14日
    瀏覽(29)
  • 200個(gè)經(jīng)典面試題(算法思想+數(shù)據(jù)結(jié)構(gòu))_1

    1. 爬樓梯 70. Climbing Stairs (Easy) 題目描述:有 N 階樓梯,每次可以上一階或者兩階,求有多少種上樓梯的方法。 定義一個(gè)數(shù)組 dp 存儲(chǔ)上樓梯的方法數(shù)(為了方便討論,數(shù)組下標(biāo)從 1 開始),dp[i] 表示走到第 i 個(gè)樓梯的方法數(shù)目。 第 i 個(gè)樓梯可以從第 i-1 和 i-2 個(gè)樓梯再走一步

    2024年02月13日
    瀏覽(22)
  • 頭歌數(shù)據(jù)結(jié)構(gòu)實(shí)訓(xùn)參考---十大經(jīng)典排序算法

    可通過 目錄 快速查閱對應(yīng)排序算法

    2024年02月04日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包