【找工作】C++和算法复习(自用)

自用随便记录

C++

排序
stl

头文件

全能头文件:

#include<bits/stdc++.h>

自定义排序函数

bool compare(const int &odd1,const int &odd2)
{
	return odd1>odd2;
}

priority_queuepq,如果是最小堆,就greater,重载运算符>。
测试:

priority_queue<int,vector<int>,greater<int>>pq;
for(int i = 0; i < 4; i++) pq.push(i);
printf("%d\n", pq.top());
>>> 0

或者自定义比较函数结构体

struct cmp{
    bool operator()(const Node& x, const Node& y){
        return x.p < y.p;
    }
};

stl

枚举map

  map<int, string> mapStudent;  
  mapStudent.insert(pair<int, string>(1, "student_one"));  
  mapStudent.insert(pair<int, string>(2, "student_two"));  
  mapStudent.insert(pair<int, string>(3, "student_three"));  
  map<int, string>::reverse_iterator  iter;  
  for(iter = mapStudent.rbegin(); iter != mapStudent.rend(); iter++)  
  {  
     cout<<iter->first<<"   "<<iter->second<<endl;  
  }  

bitset

bitset<30>b(123);//123的二进制
b.any();
b.none();
b.count();
b.test(pos);
b.set();
b.set(pos);
b.reset();
b.reset(pos);
b.to_ulong()

优先队列

算法

最短路

dijkstra

int d[maxn];
int pre[maxn];
int cost[maxn][maxn];
bool vis[maxn];

void dijkstra(int s, int n){
	memset(d, -1, sizeof(d));
	memset(pre, -1, sizeof(pre));
	for(int i = 1; i <= n; i++){
		d[i] = cost[s][i];
	}
	
	vis[s] = true;
	d[s] = 0;
	pre[s] = -1;
	
	for(int _t = 1; _t < n; _t ++){
		int k = -1;
		for(int i = 1; i <= n; i++){
			if(vis[i]) continue;
			if(k == -1 || d[i] < d[k]) k = i;
		}
		if(k == -1) break;
		vis[k] = true;
		for(int i = 1; i <= n; i++){
			if(vis[i])continue;
			if(cost[k][i] == -1) continue;
			
			int new_d = d[k] + cost[k][i];
			if(d[i] == -1 || new_d < d[i]){
				d[i] = new_d;
				pre[i] = k;
			}
		}
	}
}

floyd

void floyd(){
	for(int k = 1; k <= n; k++){
		for(int i = 1; i <= n;i++){
			for(int j = 1; j <= n; j++){
				d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
			} 
		}
	}
}

bellman-ford. 循环N-1次,对每条边松弛。如果第N次循环还可以松弛说明有负环。

并查集

https://leetcode.cn/problems/number-of-provinces/description/

const int maxn = 200+10;
class Solution {
public:
    int fa[maxn];

    int get_fa(int x){
        if(fa[x] == x) return x;
        fa[x] = get_fa(fa[x]);
        return fa[x];
    }

    int findCircleNum(vector<vector<int>>& isConnected) {
        int n = isConnected.size();

        for(int i = 1; i <= n; i++) fa[i] = i;

        for(int i = 0; i < n ;i++){
            for(int j = i; j < n;j++){// i < j
                if(isConnected[i][j] == 1){
                    int fi = get_fa(i);
                    int fj = get_fa(j);
                    fa[fj] = fi;
                }
            }
        }
        int num = 0;
        for(int i = 0; i < n; i++){
            if(i == get_fa(i)) num += 1;
            //printf("i:%d, fa:%d\n", i, get_fa(i));
        }
        return num;
    }
};

生成树

https://www.luogu.com.cn/problem/P3366
Kruscal

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int N, M;
struct Edge{
	int x, y, z;
	Edge(){
	}
	Edge(int _x, int _y, int _z){
		x = _x;
		y = _y;
		z = _z;
	}
	bool operator < (const Edge e){
		return z < e.z; 
	}
};

Edge e[maxn];
bool vis[maxn];
int fa[maxn];

int get_fa(int x){
	if(fa[x] == x) return x;
	fa[x] = get_fa(fa[x]);
	return fa[x];
}
void merge(int x, int y){
	int fx = get_fa(x);
	int fy = get_fa(y);
	fa[fx] = fy;
}

int main(){
	scanf("%d %d", &N, &M);
	for(int i = 1; i <= M; i++){
		int x, y, z;
		scanf("%d %d %d", &x, &y, &z);
		e[i] = Edge(x, y, z);
	}
	sort(e+1, e+1+M);
	for(int i = 1; i <= N; i++) fa[i] = i;

	int cost = 0;
	for(int i = 1; i <= M; i++){
		int x = e[i].x;
		int y = e[i].y;
		int fx = get_fa(x);
		int fy = get_fa(y);
		
		if(fx == fy) continue;
		
		cost += e[i].z;
		merge(x, y);
	}
	
	int vis_node = 0;
	for(int i = 1; i <= N; i++) if(fa[i] == i) vis_node += 1;
	if(vis_node == 1) printf("%d\n", cost);
	else printf("orz\n");
    return 0;
}

prim

#include <bits/stdc++.h>
using namespace std;
const int maxn = 4e5 + 10;
int N, M;
struct Edge{
	int x, y, z;
	Edge(){
	}
	Edge(int _x, int _y, int _z){
		x = _x;
		y = _y;
		z = _z;
	}
	bool operator < (const Edge e){
		return z < e.z; 
	}
};

Edge e[maxn];

int node2e[maxn];
int nex[maxn];
int d[maxn];
bool vis[maxn];

void add_edge(int node, int edge_id){
	if(node2e[node] != -1) nex[edge_id] = node2e[node];
	node2e[node] = edge_id;
}

int main(){
	
	memset(node2e, -1, sizeof(node2e));
	memset(nex, -1, sizeof(nex));
	
	
	scanf("%d %d", &N, &M);
	for(int i = 1; i <= M; i++){
		int x, y, z;
		scanf("%d %d %d", &x, &y, &z);
		e[i] = Edge(x, y, z);
		e[i+M] = Edge(y, x, z);
		
		add_edge(x, i);
		add_edge(y, i+M);
	}
	
	memset(d, -1, sizeof(d));
	memset(vis, false, sizeof(vis));
	

	int start = 1;
	vis[start] = true;
	for(int i = node2e[start]; i != -1; i = nex[i]){
		d[e[i].y]= e[i].z;
	}
	
	int cost = 0;
	bool yes = true;
	for(int t = 1; t <= N-1; t++){
		int k = -1;
		for(int i = 1; i <= N; i++){
			if(vis[i]) continue;
			if(k == -1 || d[i] < d[k]) k = i;
		}
		if(k == -1){
			yes = false;
			break;
		}
		vis[k] = true;
		cost += d[k];
		for(int i = node2e[k]; i != -1; i = nex[i]){
			int y = e[i].y;
			if(vis[y]) continue;
			if(d[y] == -1 || e[i].z < d[y]) d[y] = e[i].z;
		}
	}
	if(yes) printf("%d\n", cost);
	else printf("orz\n");
	
    return 0;
}

数据结构


树状数组
int tree[maxn<<2];
int lowbit(int x){
	return x & -x;
}
int get_sum(int idx){
	int sum = 0;
	while(idx){
		sum += tree[idx];
		idx -= lowbit(x);
	}
	return sum;
}
void update(int idx, int value){
	while(idx < LIMIT){
		tree[idx] += value;
		idx += lowbit(idx);
	}
}

数学

快速幂
gcd和最小公倍数(ab的最小公倍数=ab/gcd(ab))

int gcd(int x, int y){
    if(x<y) return gcd(y, x);
    return y == 0?x:gcd(y, x%y);
}

质数

const int limit = 1e5 + 10;

bool visp[maxn];
int prime[maxn];
int p_cnt;

void get_prime(){
	memset(visp, false, sizeof(visp));
	
	for(int i = 2; i <= limit; i++){
		if(!visp[i]) prime[++p_cnt] = i;
		for(int j = 1; j <= p_cnt; j++){
			if(i*prime[j] > limit) break;
			visp[i*prime[j]] = true;
			if(i % prime[j] == 0) break;
		}
	}
}

ex_gcd

几何

点积和叉积。
假设有两个二维向量v1(x1, y1)和v2(x2, y2)

点积
https://blog.csdn.net/apr15/article/details/106160407
v 1 ⃗ ⋅ v 2 ⃗ = x 1 x 2 + y 1 y 2 \vec{v_1}\cdot \vec{v_2} = x_1x_2+y_1y_2 v1 v2 =x1x2+y1y2
v 1 ⃗ ⋅ v 2 ⃗ \vec{v_1}\cdot \vec{v_2} v1 v2 的几何意义是: v 1 ⃗ \vec{v_1} v1 v 2 ⃗ \vec{v_2} v2 上的投影,即: v 1 ⃗ ⋅ v 2 ⃗ = ∣ v 1 ⃗ ∣ ∗ ∣ v 2 ⃗ ∣ × cos ⁡ θ \vec{v_1}\cdot \vec{v_2}=|\vec{v_1}|*|\vec{v_2}|\times \cos\theta v1 v2 =v1 v2 ×cosθ

叉积
v 1 ⃗ × v 2 ⃗ = x 1 y 1 − x 2 y 1 = ∣ v 1 ⃗ ∣ ∗ ∣ v 2 ⃗ ∣ × sin ⁡ θ \vec{v_1}\times \vec{v_2} = x_1y_1-x_2y_1=|\vec{v_1}|*|\vec{v_2}|\times \sin\theta v1 ×v2 =x1y1x2y1=v1 v2 ×sinθ
易得, ∣ v 1 ⃗ × v 2 ⃗ ∣ |\vec{v_1}\times \vec{v_2}| v1 ×v2 为两个向量共起点的时候构成的平行四边形的面积。
三维向量同理:
在这里插入图片描述

排序

https://www.luogu.com.cn/problem/P1177
https://leetcode.cn/problems/sort-an-array/description/

快速排序

思路:(假设数组从1开始到n)

  1. 每次确定一个pos,和最左边的数据交换(使得快排时的pos始终是最左边的),数值为posv。
  2. 双指针l和r指向1和n,要求最后posv左边的值都小于等于posv,右边的值都大于等于posv,最后posv的值为p。
  3. 因为需要最后确定位置p,如果循环是while(l<r),初始值l永远不能到达n+1。对于循环过程while(??? &&v[l]<=posv)l++;,跳出循环的可能是v[l]>posv,v[l-1]<=posv,因此p可以是l-1。而如果l不能到达n+1,l-1就不能到达n,这是不合理的。所以循环应该为while(l<=r)
  4. 代码如下:
void _kuaipai(int l, int r){
	if(l>=r) return;
	int LL=l, RR=r; 
	int pos = LL + (r-l)/2;
	swap(v[l], v[pos]);
	int posv = v[l];
	
	while(l<=r){
		while(l<=r && v[l]<=posv)l++;
		while(l<=r && v[r]>=posv)r--;
		if(l<=r) swap(v[l], v[r]); 
	}
	// v[l]> posv || l==n+1
	int p = l-1;
	swap(v[LL], v[p]);

	_kuaipai(LL, p-1);
	_kuaipai(p+1, RR);
}

超时问题:比如数组长度为1000,所有数据都相同都是5。那么每次p都在最后一个数,复杂度为O(n^2)。
参考力扣的一种题解,可以把小于等于posv的放在左边,大于posv的放在右边。然后对左边再做一次快排,把小于posv的放左边,等于posv的放右边。

#include<bits/stdc++.h>
#include <cstdlib> 
#include <ctime>
using namespace std;
const int maxn = 1e5 + 10;
int n;
int v[maxn];

void output(int l, int r){
	for(int i = l; i <= r; i++){
		printf("%d", v[i]);
		if(i != r) printf(" ");
		else printf("\n");
	}
}

void _swap(int &a, int&b){
	int tmp = a;
	a = b;
	b = tmp;
}

int _sub_kuaipai(int l, int r){
	int posv = v[r];
	_swap(v[l], v[r]);// v[r] == posv
	while(l<=r){
		while(l<=r && v[l]<posv)l++;//l==n+1 || v[l]>=posv
		while(l<=r && v[r]>=posv)r--;
		if(l<=r) _swap(v[l], v[r]);
	}
	// v[l-1] < posv
	return l-1;
}
void _kuaipai(int l, int r){
	if(l>=r) return;
	int LL=l, RR=r; 
	srand(time(0));
	int tmp = rand() % (r-l+1);
	int pos = LL + tmp;
	swap(v[l], v[pos]);
	int posv = v[l];
	
	while(l<=r){
		while(l<=r && v[l]<=posv)l++;//l==n+1 || v[l]>posv
		while(l<=r && v[r]>posv)r--;
		if(l<=r) _swap(v[l], v[r]); 
	}
	// v[l]> posv || l==n+1
	int p = l-1;
	_swap(v[LL], v[p]);
	int p1 = _sub_kuaipai(LL, p);
	
//	printf(">>> L:%d, R:%d, posv:%d, p:%d\n", LL, RR, posv, p);
//	output(LL, RR);
	_kuaipai(LL, p1);
	_kuaipai(p+1, RR);
}

void kuaipai(){
	_kuaipai(1, n);
} 

int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) scanf("%d", &v[i]);
	
	kuaipai();
	output(1, n);
	return 0;
} 
堆排序
#include<bits/stdc++.h>
#include <cstdlib> 
#include <ctime>
using namespace std;
const int maxn = 1e5 + 10;
int n;
int v[maxn];

void output(int l, int r){
	for(int i = l; i <= r; i++){
		printf("%d", v[i]);
		if(i != r) printf(" ");
		else printf("\n");
	}
}

void _swap(int &a, int&b){
	int tmp = a;
	a = b;
	b = tmp;
}

int hp[maxn]; 
void add_value(int num, int val){// 第num个数为val
	int p = num;
	hp[num] = val;
	while(1){
		int fa = p>>1;//3-1,2-1
		if(fa == 0) break;
		if(hp[p]<=hp[fa]) break;
		else{
			_swap(hp[p], hp[fa]);
			p = fa;
		} 
	} 
	
}
void duipai(){
	// 构建最大堆 
	for(int i = 1; i <= n; i++){
		add_value(i, v[i]);
	}
	//for(int i = 1; i <= n; i++) printf("%d\n", hp[i]);
	// 排序
	for(int i = n; i >= 2; i--){
		int num = i-1;
		_swap(hp[1], hp[i]);
		// 下沉hp[1];
		int p = 1;
		while(p <= num){
			int ls = p<<1;
			int rs = p<<1|1;
			
			if(ls>num) break;
			int idx = ls;
			if(rs<=num && hp[rs] > hp[idx]) idx = rs;
			
			if(hp[p] < hp[idx]){
				_swap(hp[p], hp[idx]);
				p = idx;
			}
			else{
				break;
			}
		} 
	} 
	for(int i = 1; i <= n; i++) v[i] = hp[i];
}

int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) scanf("%d", &v[i]);

	duipai();
	output(1, n);
	return 0;
} 
归并排序
#include<bits/stdc++.h>
#include <cstdlib> 
#include <ctime>
using namespace std;
const int maxn = 1e5 + 10;
int n;
int v[maxn];

void output(int l, int r){
	for(int i = l; i <= r; i++){
		printf("%d", v[i]);
		if(i != r) printf(" ");
		else printf("\n");
	}
}

void _swap(int &a, int&b){
	int tmp = a;
	a = b;
	b = tmp;
}

int temp[maxn];
void _merge(int l, int r){
	if(l>=r) return;
	int p = (l+r)>>1;
	
	_merge(l, p);
	_merge(p+1, r);

	for(int i = l; i <= r; i++) temp[i] = v[i];
	int p1 = l, p2 = p+1;
	int idx = l;
	while(p1<=p && p2<=r){
		if(temp[p1] < temp[p2]) v[idx++] = temp[p1++];
		else  v[idx++] = temp[p2++];
	}
	while(p1<=p)v[idx++] = temp[p1++];
	while(p2<=r)v[idx++] = temp[p2++];
}

void merge_sort(){
	_merge(1, n); 
}


int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) scanf("%d", &v[i]);

	merge_sort();
	output(1, n);
	return 0;
} 

字符串

manacher

找最长回文子串

void initialize(int n, char ch[maxn]){
	int nn = n<<1|1;
	for(int i = nn-1, j=n-1; i>=2; i-=2){
		ch[i] = '#';
		ch[i-1] = ch[j];
	}
	ch[0] = '#';
}

void manacher(int n, char ch[maxn]){
	memset(d, 0, sizeof(d));//d[i]是不包括i在内的半径
	int mid = -1;
	int maxr = -1;
	for(int i = 0; i < n; i++){
		if(maxr>d[i]){
			int other = mid * 2 - i;
			d[i] = min(d[other], maxr-i);
		}
		while(i-d[i]>=0 && i+d[i]<n && ch[i-d[i]]==ch[i+d[i]])i++;
		d[i]--;
		if(i+d[i]>maxr){
			mid = i;
			maxr = i+d[i];
		}
	}
}
kmp

模式匹配
前缀函数https://oi-wiki.org/string/kmp/
特点1:“一个重要的观察是 相邻的前缀函数值至多增加 1。”
特点2:当不符合最优的增加1的情况的时候,如何快速找到下一个可以匹配的对象?
注意 前缀数组pi[0]=0!!!
其他情况下 表示的是重复前后缀的长度,比如对于abab字符串,pi[3]=2(有重复串ab)

KMP:给定一个文本 t 和一个字符串 s,我们尝试找到并展示 s 在 t 中的所有出现(occurrence)
力扣测试题:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/

const int maxn = 1e4 + 10;
class Solution {
public:
    int pi[maxn];//前缀数组

    void get_pi(string s){
        int n = s.length();
        memset(pi, 0, sizeof(pi));
        for(int i = 1; i < n; i++){
            int j = pi[i-1];
            while(j != 0 && s[j] != s[i]){
                j = pi[j-1];
            }
            if(s[i] == s[j]) pi[i] = j+1;
            else pi[i] = 0;
        }
    }

    int strStr(string haystack, string needle) {
        int n_needle = needle.length();
        get_pi(needle);

        int n = haystack.length();
        int j = 0;
        for(int i = 0; i < n; i++){
            while(j != 0 && haystack[i] != needle[j]){
                j = pi[j-1];
            }
            if(haystack[i] == needle[j]){
                j++;
            }
            //printf("i:%d, ch:%c, j:%d, chj:%c\n", i, haystack[i], j, needle[j]);
            if(j == n_needle) return i - n_needle + 1;
        }
        return -1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值