最新算法基础课 acwing,springcloud实战视频

面试资料整理汇总

成功从小公司跳槽进蚂蚁定级P7,只因刷了七遍这些面试真题

成功从小公司跳槽进蚂蚁定级P7,只因刷了七遍这些面试真题

这些面试题是我朋友进阿里前狂刷七遍以上的面试资料,由于面试文档很多,内容更多,没有办法一一为大家展示出来,所以只好为大家节选出来了一部分供大家参考。

面试的本质不是考试,而是告诉面试官你会做什么,所以,这些面试资料中提到的技术也是要学会的,不然稍微改动一下你就凉凉了

在这里祝大家能够拿到心仪的offer!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

using namespace std;

int main(){

int n = 10;

for(int k = 3;k >= 0;k-- ) printf(“%d”,(n>>k)&1);

return 0;

}

lizi

lowbit运算

image-20210830153204218

image-20210830153435293

二进制中1的个数

https://www.acwing.com/problem/content/803/

#include <bits/stdc++.h>

using namespace std;

int lowbit(int x){

return x & -x;

}

int main(){

int n;

scanf(“%d”,&n);

while(n–){

int x;

scanf(“%d”,&x);

int res = 0;

// 每次减去x的最后一位1

while(x) x -= lowbit(x), res++;

printf("%d ",res);

}

return 0;

}

离散化

lisanhjua

image-20210830154951470

区间和

https://www.acwing.com/problem/content/804/

#include <bits/stdc++.h>

using namespace std;

typedef pair<int,int> PII;

const int N = 3e5 + 10;

int n,m;

int a[N],s[N];

vector alls;

vector add,query;

// 通过x的值找到下标,将一个值序列,映射到从1开始的数组

int find(int x){

int l = 0,r = alls.size() - 1;

while(l < r){

int mid = (l + r) >> 1;

if(alls[mid] >= x) r = mid;

else l = mid + 1;

}

return r + 1;

}

int main(){

scanf(“%d%d”,&n,&m);

for(int i = 0;i < n;i++){

int x,c;

scanf(“%d%d”,&x,&c);

add.push_back({x,c});

alls.push_back(x);

}

for(int i = 0;i < m;i++){

int l,r;

scanf(“%d%d”,&l,&r);

query.push_back({l,r});

alls.push_back(l);

alls.push_back®;

}

// 去重

sort(alls.begin(),alls.end());

alls.erase(unique(alls.begin(),alls.end()),alls.end());

// 上面操作完,是一个去重并且排序后的一个数组

// 处理插入

for(auto item: add) {

int x = find(item.first);

// 上面x是通过值找到的下标,x是下标

a[x] += item.second;

}

// 预处理前缀和

for(int i= 1;i <= alls.size();i++) s[i] = s[i-1] + a[i];

// 处理询问

for(auto item : query) {

int l = find(item.first);

int r = find(item.second);

printf(“%d\n”,s[r] - s[l-1]);

}

return 0;

}

区间合并

merge

区间合并

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2x7KVK5l-1630933432558)(算法基础课.assets/image-20210830163830687.png)]

https://www.acwing.com/problem/content/805/

#include<bits/stdc++.h>

using namespace std;

typedef pair<int,int> PII;

const int N = 1e5 + 10;

int n;

vector segs;

void merge(vector &segs){

vector res;

// 以左端点排序

sort(segs.begin(),segs.end());

int st = -2e9,ed = -2e9;

for(auto seg : segs){

// 没有交集

if(ed < seg.first){

if(st != -2e9) res.push_back({st,ed});

st = seg.first,ed = seg.second;

}else ed = max(ed,seg.second);

}

// 最后一个

if(st != -2e9) res.push_back({st,ed});

segs = res;

}

int main(){

scanf(“%d”,&n);

for(int i = 0;i < n;i++){

int l,r;

scanf(“%d%d”,&l,&r);

segs.push_back({l,r});

}

merge(segs);

printf(“%d\n”,segs.size());

return 0;

}

第二讲 数据结构


单链表

image-20210831153657064

用数组模拟链表

e数组存值,ne数组存next

image-20210831153802072

单链表

https://www.acwing.com/problem/content/828/

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

// head 表示头结点的下标

// e[i] 表示节点i的值

// ne[i] 表示节点i的next指针是多少

// 存储到当前用到了哪个点

int head,inx,e[N],ne[N];

// 初始化

void init(){

// 初始化,链表为空,-1表示空集

head = -1;

inx = 0;

}

// 将x插到头结点,就是让x成为头结点

void add_to_head(int x) {

e[inx] = x;

ne[inx] = head;

// head 表示头结点的下标,head不是一个节点哦

head = inx;

inx++;

}

// 将x插入到下标是k的节点的后面

void add(int k,int x){

e[inx] = x;

ne[inx] = ne[k];

ne[k] = inx;

inx++;

}

// 将下标是k的点的后面的点删除

void remove(int k){

ne[k] = ne[ne[k]];

}

int main(){

int M;

scanf(“%d”,&M);

init();

while(M–){

int k,x;

char op;

cin >> op;

if(op == ‘H’){

scanf(“%d”,&x);

add_to_head(x);

}else if(op == ‘D’){

scanf(“%d”,&k);

// 删除头结点,就是让head指向头结点的下一个

if (!k) head = ne[head];

else remove(k-1);

}else{

scanf(“%d%d”,&k,&x);

add(k-1,x);

}

}

for(int i = head;i != -1;i = ne[i]) printf("%d ",e[i]);

return 0;

}

双链表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jF276k9j-1630933432561)(算法基础课.assets/image-20210831153743826.png)]

image-20210831162815817

双链表

https://www.acwing.com/problem/content/829/

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int e[N],l[N],r[N],idx;

// 初始化

void init(){

// 0 表示右端点

// 1 表示左端点

r[0] = 1,l[1] = 0;

idx = 2;

}

// 在下标是k的点的右边,插入x

void add(int k,int x){

e[idx] = x;

l[idx] = k;

r[idx] = r[k];

r[k] = idx;

l[r[idx]] = idx;

idx++;

}

// 删除第k个点

void remove(int k) {

r[l[k]] = r[k];

l[r[k]] = l[k];

}

int main(){

int M;

scanf(“%d”,&M);

init();

while(M–){

int x,k;

string op;

cin >> op;

if(op == “L”){

scanf(“%d”,&x);

add(0,x);

}else if(op == “R”){

scanf(“%d”,&x);

add(l[1],x);

}else if(op == “D”){

scanf(“%d”,&k);

// idx从2开始,第k个点的下标应该是k+1

remove(k+1);

}else if(op == “IL”){

scanf(“%d%d”,&k,&x);

add(l[k+1],x);

}else{

scanf(“%d%d”,&k,&x);

add(k+1,x);

}

}

for(int i = r[0];i != 1;i = r[i]) printf("%d ",e[i]);

return 0;

}

先进后出

模拟栈

https://www.acwing.com/problem/content/830/

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

// tt 是栈顶坐标

int stk[N],tt;

void push(int x) {

stk[++tt] = x;

}

void pop(){

tt–;

}

bool empty(){

if(tt == 0) return true;

else return false;

}

int query(){

return stk[tt];

}

int main(){

int M;

scanf(“%d”,&M);

while(M–){

string op;

int x;

cin >>op;

if(op == “push”){

scanf(“%d”,&x);

push(x);

}else if(op == “pop”){

pop();

}else if(op == “query”){

printf(“%d\n”,query());

}else{

if(empty()) printf(“YES\n”);

else printf(“NO\n”);

}

}

return 0;

}

队列

先进先出

模拟队列

https://www.acwing.com/problem/content/831/

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5+10;

// 在队尾插入元素,在队头弹出原始

int q[N],hh,tt = -1;

void push(int x) {

q[++ tt] = x;

}

void pop(){

hh++;

}

bool empty(){

if(hh <= tt) return false;

else return true;

}

int query(){

return q[hh];

}

int main(){

int M;

scanf(“%d”,&M);

while(M–){

string op;

int x;

cin >> op;

if(op == “push”){

scanf(“%d”,&x);

push(x);

}else if(op == “pop”){

pop();

}else if(op == “query”){

printf(“%d\n”,query());

}else{

if(empty()) printf(“YES\n”);

else printf(“NO\n”);

}

}

return 0;

}

单调栈

image-20210831184549374

单调栈

常见模型:找出每个数左边离它最近的比它大/小的数

https://www.acwing.com/problem/content/description/832/

O(n)

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int n;

// tt一开始指向0,指向0表示没有元素

int stk[N],tt;

int main(){

scanf(“%d”,&n);

for(int i = 0;i < n;i++){

int x;

scanf(“%d”,&x);

// 如果栈不空,并且栈顶元素大于x,弹栈

while(tt && stk[tt] >= x) tt–;

// 如果栈不空,输出栈顶

if(tt) printf("%d ",stk[tt]);

else printf("-1 ");

// 压栈,因为对于后面的元素而言,这个是离它最近,并且小的数了

stk[++tt] = x;

}

return 0;

}

单调队列

常见模型:找出滑动窗口中的最大值/最小值

base on 董晓 : https://www.bilibili.com/video/BV1H5411j7o6

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R3TivCQf-1630933432561)(https://gitee.com/Crescent_P/picture-bed/raw/master/image-20210901142939496.png)]

image-20210901143254248

image-20210901143506485

滑动窗口

https://www.acwing.com/problem/content/156/

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10;

int a[N],q[N],hh,tt = -1;

int main(){

int n,k;

scanf(“%d%d”,&n,&k);

for(int i = 0;i < n;i++) scanf(“%d”,&a[i]);

for(int i = 0;i < n;i++){

// q[hh] 不在[i-k+1,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) printf("%d ",a[q[hh]]);

}

puts(“”) ;

hh = 0,tt = -1;

for(int i = 0;i < n;i++){

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]]);

}

return 0;

}

KMP

image-20210901152508092

image-20210901153639974

image-20210901154845219

KMP字符串

https://www.acwing.com/problem/content/833/

#include <bits/stdc++.h>

using namespace std;

const int N = 1e4+10,M = 1e5+10;

int n,m;

char p[N],s[M];

int ne[N];

int main(){

// 从第1位开始

cin >> n >> p+1 >> m >> s+1;

// 求next数组

// next[1]=0,因为是j+1来匹配

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){

// 下标从1开始的所以要减去1 ,应该是 i-n+1-1

printf("%d ",i-n);

j = ne[j]; //

}

}

return 0;

}

Trie

高效地存储和查找字符串集合的数据结构

要么全是大写,要么全是小写,要么全是数字,类型不会特别多

image-20210901161557289

Trie字符串统计

https://www.acwing.com/problem/content/837/

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

// 下标是0的点,既是根节点,又是空节点

int son[N][26], cnt[N],idx;

char str[N];

void insert(char str[]){

// 从根节点开始

int p = 0;

// c++ 字符串以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[0] == ‘I’) insert(str);

else printf(“%d\n”,query(str));

}

}

并查集

image-20210901165836918

合并集合

https://www.acwing.com/problem/content/838/

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int n,m;

int p[N];

// 返回x祖宗节点 + 路径压缩

int find(int x){

// 如果不是根节点,就让他的父节点等于祖宗节点

if(p[x] != x) p[x] = find(p[x]);

return p[x];

}

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’){

// a的祖宗节点的父节点 = b的祖宗节点

p[find(a)] = find(b);

}else{

if(find(a) == find(b)) puts(“Yes”);

else puts(“No”);

}

}

return 0;

}

连通块中点的数量

https://www.acwing.com/problem/content/839/

#include <bits/stdc++.h>

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];

}

int main(){

scanf(“%d%d”,&n,&m);

for(int i = 1;i <= n;i++){

p[i] = i;

size[i] = 1;

}

while(m–){

int a,b;

char op[2];

scanf(“%s”,op);

if(op[0] == ‘C’){

scanf(“%d%d”,&a,&b);

if(find(a) != find(b)) size[p[b]] += size[p[a]];

p[find(a)] = find(b);

}else if(op[1] == ‘1’){

scanf(“%d%d”,&a,&b);

if(find(a) == find(b)) puts(“Yes”);

else puts(“No”);

}else{

scanf(“%d”,&a);

printf(“%d\n”,size[find(a)]);

}

}

return 0;

}

heap

image-20210902115348563

image-20210902120100393

哈希表

image-20210903191406675

STL

/*

STL

vector 变长数组,倍增

size() 返回元素个数

empty() 返回是否为空

clear() 清空

front()/back()

push_back/pop_back()

begin()/end()

[]

pair<int,int>

first 第一个元素

second 第二个元素

支持比较运算,按字典序,以first为第一关键字

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

size()/length()

empty()

clear()

queue 队列

push() 向队尾插入一个元素

front() 返回队头元素

back() 返回队尾元素

pop() 弹出队头元素

priortity_queue 优先队列,默认是大根堆

push() 插入一个元素

top() 返回堆顶元素

pop() 弹出队头元素

stack 栈

push() 向栈顶插入元素

top() 返回栈顶元素

pop() 弹出栈顶的元素

size()

empty()

deque 双端队列

size()

empty()

clear()

front()

back()

push_back()/pop_back()

push_front()/pop_front()

begin()/end()

[]

set,map,multiset,multimap 基于平衡二叉树(红黑树),动态维护有序序列

size()

empty()

clear()

begin()/end() ++,-- 返回前驱和后继

set/multiset

insert() 插入一个数

find() 查找一个数

count() 返回一个数的个数

erase()

(1) 输入是一个数X,删除所有的X O(k+logn)

(2) 输入是一个迭代器,删除这个迭代器

lower_bound/upper_bound()

lower_bound(x) 返回大于等于x的最小的数的迭代器

upper_bound(x) 返回大于x的最小的数的迭代器

map/multimap

insert() 插入的是一个pair

erase() 输入的是pair或者迭代器

find()

[] O(logn)

lower_bound/upper_bound()

// 无序的

unordered_set,unordered_map,unordered_multiset,unordered_multimap 哈希表

和上面类似,增删改查的时间复杂度是O(1)

不支持 lower_bound/upper_bound(),迭代器的++,–

bitset 压位

*/

#include <bits/stdc++.h>

using namespace std;

int main() {

// vector

// 定义vector

vector va;

vector vb(10);

//长度为10,并且每个元素都是3

vector vc(10,3);

for(int i = 0;i < 10;i++) va.push_back(i);

// 三种遍历方式

for(int i = 0;i < 10;i++) printf("%d ",va[i]);

puts(“”);

for(vector::iterator i = va.begin();i != va.end();i++) printf("%d ",*i);

puts(“”);

for(auto x : va) printf("%d ",x);

puts(“”);

// pair

pair<int,string> p;

p = make_pair(1,“cp”);

p = {20,“cpcp”};

// string

string sa = “123”;

sa += “456”;

cout << sa << endl;

// 子串,第一个参数起始地址,第二个参数长度

cout << sa.substr(2,4) << endl;

// c_str(),字符串起始的长度

printf(“%s\n”,sa.c_str());

// queue 队列

queue q;

// q = queue;

// 优先队列

priority_queue heap; // 大根堆

// priority_queue<int,vector<int,greater> heap; // 小根堆

// set

// map

map<string,int> ma;

ma[“cp”] = 1;

printf(“%d”,ma[“cp”]);

return 0;

}

第三讲 搜索与图论


image-20210904101542540

DFS

每个DFS都对应了一个搜索树

image-20210904103614048

排列数字

https://www.acwing.com/problem/content/844/

#include <bits/stdc++.h>

using namespace std;

const int N = 10;

int n,path[N];

bool st[N];

void dfs(int u){

if(u == n) {

for(int i = 0;i < n;i++) printf("%d ",path[i]);

puts(“”);

return;

}

for(int i = 1;i <=n;i++){

if(!st[i]) {

path[u] = i;

st[i] = true;

dfs(u+1);

// 恢复现场

st[i] = false;

path[u] = 0;

}

}

}

int main(){

scanf(“%d”,&n);

dfs(0);

return 0;

}

BFS

image-20210904142518897

走迷宫

https://www.acwing.com/problem/content/846/

#include <bits/stdc++.h>

using namespace std;

typedef pair<int,int> PII;

const int N =110;

int n,m;

int g[N][N];

int d[N][N];

queue q;

int bfs(){

q.push({0,0});

memset(d,-1,sizeof d);

d[0][0] = 0;

int dx[4] = {1,0,-1,0},dy[4] = {0,1,0,-1};

while(!q.empty()){

auto t = q.front();

q.pop();

for(int i = 0;i < 4;i++){

int x = t.first + dx[i];

int y = t.second + dy[i];

if(x >= 0 && x < n && y >= 0 && y < m && g[x][y] == 0 && d[x][y] == -1){

q.push({x,y});

d[x][y] = d[t.first][t.second] + 1;

}

}

}

return d[n-1][m-1];

}

int main(){

scanf(“%d%d”,&n,&m);

for(int i = 0;i < n;i++){

for(int j = 0;j < m;j++) scanf(“%d”,&g[i][j]);

}

printf(“%d\n”,bfs());

return 0;

}

树与图的深度优先遍历

在算法题中,不管是有向图还是无向图,我们都视为有向图

如果是无向图,那么我们就设置一条a->b,再设置一条b->a的边就行了

image-20210904150009527

图的深搜

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10,M = N * 2;

int n,m;

int h[N],e[M],ne[M],idx;

bool st[N];

// 在a的链接表中,插入一个b

void add(int a,int b){

// 头插法

n[idx] = b;

ne[idx] = h[a];

h[a] = idx++;

}

// 深搜

void dfs(int u){

// 标记一下,已经被搜索过了

st[u] = true;

// 遍历连接表

for(int i = h[u];i != -1;i = ne[i]){

int j = e[i];

if(!st[j]) dfs(j);

}

}

int main(){

// 都没有连接,-1表示尾节点

memset(h,-1,sizeof h);

}

树的重心

https://www.acwing.com/problem/content/description/848/

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10,M = N * 2;

int n,m;

// h[N]就是头节点,只是因为有多个链表,所以变为数组了

int h[N],e[M],ne[M],idx;

bool st[N];

int ans = N;

// 在a的链接表中,插入一个b

void add(int a,int b){

// 头插法

e[idx] = b;

ne[idx] = h[a];

h[a] = idx++;

}

// 以u为根的子树中点的数量

int dfs(int u){

// 标记一下,已经被搜索过了

st[u] = true;

// sum 当前子树的大小

// res 每个连通块大小的最大值

int sum = 1,res = 0;

// 遍历连接表

for(int i = h[u];i != -1;i = ne[i]){

// j 是相邻的点

int j = e[i];

if(!st[j]) {

// 与u相邻的点的子树的节点个数

int s = dfs(j);

// 找出连通块的最大值

res = max(res,s);

// 当前子树的大小,要加上当前点各个子节点为根的子树的大小

sum += s;

}

}

// n - sum 是上面连通块的节点个数

res = max(res,n - sum);

// res是连通块的最大值,我们要找到连通块最大的最小值

ans = min(res,ans);

return sum;

}

int main(){

cin >> n;

// 都没有连接,-1表示尾节点

memset(h,-1,sizeof h);

for(int i = 0;i < n;i++){

int a,b;

cin >> a >> b;

add(a,b);

add(b,a);

}

dfs(1);

cout << ans << endl;

return 0;

}

树与图的广度优先遍历

image-20210904154454144

图中点的层次

https://www.acwing.com/problem/content/849/

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int n,m;

int h[N],e[N],ne[N],idx;

int d[N];

queue q;

void add(int a,int b){

e[idx] = b;

ne[idx] = h[a];

h[a] = idx++;

}

int bfs(){

q.push(1);

memset(d,-1,sizeof d);

d[1] = 0;

while(!q.empty()){

int t = q.front();

q.pop();

for(int i = h[t];i != -1;i=ne[i]){

int j = e[i];

if(d[j] == -1){

d[j] = d[t]+1;

q.push(j);

}

}

}

return d[n];

}

int main(){

cin >> n >> m;

memset(h,-1,sizeof h);

for(int i = 0;i < m;i++){

int a,b;

scanf(“%d%d”,&a,&b);

add(a,b);

}

printf(“%d\n”,bfs());

return 0;

}

拓扑排序

image-20210904160421879

入度为零都可以作为起点

image-20210904160745496

有向图的拓扑序列

https://www.acwing.com/problem/content/description/850/

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int n,m;

int h[N],e[N],ne[N],idx;

int q[N],d[N];

void add(int a,int b){

e[idx] = b;

ne[idx] = h[a];

h[a] = idx++;

}

bool topsort(){

int hh = 0,tt =-1;

for(int i = 1;i <= n;i++) {

// 入度为0的点入队,队尾入队

if(!d[i]) q[++tt] = i;

}

while(hh <= tt) {

// 队头出队

int t = q[hh++];

for(int i = h[t];i != -1;i = ne[i]){

int j = e[i];

// 删除i->j,就删除了j的入度

d[j]–;

// j 入队

if(d[j] == 0) q[++tt]=j;

}

}

// 队尾到n-1,表示全部加入,没有环

return tt == n -1;

}

int main(){

cin >> n >> m;

memset(h,-1,sizeof h);

for(int i = 0;i < m;i++){

int a,b;

cin >> a >> b;

add(a,b);

// 入度

d[b]++;

}

if(topsort()){

for(int i = 0;i < n;i++) {

printf("%d ",q[i]);

}

}else puts(“-1”);

return 0;

}

最短路问题

单源:只有一个起点

多源:有多个起点

image-20210906180430125

稠密图:m~n^2 : 邻接矩阵,因为点多

稀疏图:m~n : 邻接表

朴素Dijkstra

image-20210906181928773

Dijkstra求最短路 I

https://www.acwing.com/problem/content/851/

#include <bits/stdc++.h>

using namespace std;

const int N = 510;

int n,m;

// 稠密图,因为点多,用邻接矩阵

int g[N][N];

int dist[N];

bool st[N];

int dijkstra(){

// 初始化距离都为正无穷

memset(dist,0x3f,sizeof dist);

dist[1] = 0;

// 迭代n次

for(int i = 0;i < n;i++){

int t = -1;

// 每次找S中距离最小的点

for(int j = 1;j <= n;j++){

// t == -1 表示是第一个不在S中的点

// dist[t] > dist[j] 表示找到最小值

if(!st[j] && (t == -1 || dist[t] > dist[j])) t = j;

}

// t这个点用过了

st[t] = true;

for(int j = 1;j <= n;j++) {

// g[t][j] t到j的距离

// 更新距离

dist[j] = min(dist[j],dist[t] + g[t][j]);

}

}

if(dist[n] == 0x3f3f3f3f) return -1;

return dist[n];

}

int main(){

scanf(“%d%d”,&n,&m);

// 初始化

memset(g,0x3f,sizeof g);

// 因为边的权值都是正的,所以存在自环也没关系,因为最短路不可能走自环

while(m–){

int a,b,c;

scanf(“%d%d%d”,&a,&b,&c);

// 有重边,选最短的

g[a][b] = min(g[a][b],c);

}

int t = dijkstra();

printf(“%d\n”,t);

return 0;

}

最后我们该如何学习?

1、看视频进行系统学习

这几年的Crud经历,让我明白自己真的算是菜鸡中的战斗机,也正因为Crud,导致自己技术比较零散,也不够深入不够系统,所以重新进行学习是很有必要的。我差的是系统知识,差的结构框架和思路,所以通过视频来学习,效果更好,也更全面。关于视频学习,个人可以推荐去B站进行学习,B站上有很多学习视频,唯一的缺点就是免费的容易过时。

另外,我自己也珍藏了好几套视频资料躺在网盘里,有需要的我也可以分享给你:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

2、读源码,看实战笔记,学习大神思路

“编程语言是程序员的表达的方式,而架构是程序员对世界的认知”。所以,程序员要想快速认知并学习架构,读源码是必不可少的。阅读源码,是解决问题 + 理解事物,更重要的:看到源码背后的想法;程序员说:读万行源码,行万种实践。

Spring源码深度解析:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

Mybatis 3源码深度解析:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

Redis学习笔记:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

Spring Boot核心技术-笔记:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

3、面试前夕,刷题冲刺

面试的前一周时间内,就可以开始刷题冲刺了。请记住,刷题的时候,技术的优先,算法的看些基本的,比如排序等即可,而智力题,除非是校招,否则一般不怎么会问。

关于面试刷题,我个人也准备了一套系统的面试题,帮助你举一反三:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

只有技术过硬,在哪儿都不愁就业,“万般带不去,唯有业随身”学习本来就不是在课堂那几年说了算,而是在人生的旅途中不间断的事情。

人生短暂,别稀里糊涂的活一辈子,不要将就。

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

n >> a >> b;

add(a,b);

// 入度

d[b]++;

}

if(topsort()){

for(int i = 0;i < n;i++) {

printf("%d ",q[i]);

}

}else puts(“-1”);

return 0;

}

最短路问题

单源:只有一个起点

多源:有多个起点

image-20210906180430125

稠密图:m~n^2 : 邻接矩阵,因为点多

稀疏图:m~n : 邻接表

朴素Dijkstra

image-20210906181928773

Dijkstra求最短路 I

https://www.acwing.com/problem/content/851/

#include <bits/stdc++.h>

using namespace std;

const int N = 510;

int n,m;

// 稠密图,因为点多,用邻接矩阵

int g[N][N];

int dist[N];

bool st[N];

int dijkstra(){

// 初始化距离都为正无穷

memset(dist,0x3f,sizeof dist);

dist[1] = 0;

// 迭代n次

for(int i = 0;i < n;i++){

int t = -1;

// 每次找S中距离最小的点

for(int j = 1;j <= n;j++){

// t == -1 表示是第一个不在S中的点

// dist[t] > dist[j] 表示找到最小值

if(!st[j] && (t == -1 || dist[t] > dist[j])) t = j;

}

// t这个点用过了

st[t] = true;

for(int j = 1;j <= n;j++) {

// g[t][j] t到j的距离

// 更新距离

dist[j] = min(dist[j],dist[t] + g[t][j]);

}

}

if(dist[n] == 0x3f3f3f3f) return -1;

return dist[n];

}

int main(){

scanf(“%d%d”,&n,&m);

// 初始化

memset(g,0x3f,sizeof g);

// 因为边的权值都是正的,所以存在自环也没关系,因为最短路不可能走自环

while(m–){

int a,b,c;

scanf(“%d%d%d”,&a,&b,&c);

// 有重边,选最短的

g[a][b] = min(g[a][b],c);

}

int t = dijkstra();

printf(“%d\n”,t);

return 0;

}

最后我们该如何学习?

1、看视频进行系统学习

这几年的Crud经历,让我明白自己真的算是菜鸡中的战斗机,也正因为Crud,导致自己技术比较零散,也不够深入不够系统,所以重新进行学习是很有必要的。我差的是系统知识,差的结构框架和思路,所以通过视频来学习,效果更好,也更全面。关于视频学习,个人可以推荐去B站进行学习,B站上有很多学习视频,唯一的缺点就是免费的容易过时。

另外,我自己也珍藏了好几套视频资料躺在网盘里,有需要的我也可以分享给你:

[外链图片转存中…(img-rAPjMIX2-1715679269022)]

2、读源码,看实战笔记,学习大神思路

“编程语言是程序员的表达的方式,而架构是程序员对世界的认知”。所以,程序员要想快速认知并学习架构,读源码是必不可少的。阅读源码,是解决问题 + 理解事物,更重要的:看到源码背后的想法;程序员说:读万行源码,行万种实践。

Spring源码深度解析:

[外链图片转存中…(img-aYyHxt3Y-1715679269023)]

Mybatis 3源码深度解析:

[外链图片转存中…(img-6sXy0YSO-1715679269023)]

Redis学习笔记:

[外链图片转存中…(img-WKS0us8K-1715679269023)]

Spring Boot核心技术-笔记:

[外链图片转存中…(img-U8rCBbd7-1715679269024)]

3、面试前夕,刷题冲刺

面试的前一周时间内,就可以开始刷题冲刺了。请记住,刷题的时候,技术的优先,算法的看些基本的,比如排序等即可,而智力题,除非是校招,否则一般不怎么会问。

关于面试刷题,我个人也准备了一套系统的面试题,帮助你举一反三:

[外链图片转存中…(img-MQUPwfhc-1715679269024)]

只有技术过硬,在哪儿都不愁就业,“万般带不去,唯有业随身”学习本来就不是在课堂那几年说了算,而是在人生的旅途中不间断的事情。

人生短暂,别稀里糊涂的活一辈子,不要将就。

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值